본문 바로가기

Programming/C++

try – catch, throw

-예외처리- try – catch, throw

 

지금까지 알면서도 사용하지 않았던 try -catch문... 꼭 사용할 이유없이 if문등으로 예외처리는 가능하지만 보다 명확하고 명시적으로 코드를 보여주기위해선 꼭 필요하다는 사실이 요즘 들어 느끼게 되어 다시 "게임개발자를 위한 C++ 책"에서 그 내용을  찾아 정리해본다. 

 

프로그램 코드에서 예외가 발생할 것 같은 부분은 특정한 몇 곳이다. , 코드의 일부 예를 들면 5% - 에서만 예외 처리를 수행할지도 모른다. 이러한 부분이 문법적으로 명시된다면 프로그램을 유지 보수하는데 많은 이득이 있을 것이다.

 

if문으로 예외처리가능하지만 구지 try catch문 안에 넣은 이유가 바로 문법적인 명시때문이다.!

 

void main() {

             int i=5, j=2, k=0;

 

             //이문장은try블럭안에포함되지않으므로. 예외처리를하지않는다는것을보장한다.

             cout<< "begin" <<endl;

 

             //try 블럭안에포함된문장중에서에러가발생할수도있을것이라는보장을한다.

             //try 블럭은확실히예외를해야하는코드와그렇지않는코드를구조적으로구분한다.

             try{

            

                           if(j==100 || j==0) throw j;

                           cout  <<"첫번째:" << i/j <<endl;

                          if(k==100 || k==0) throw k; //k0이므로 catch쪽으로 k가 보내짐

                           cout  <<"두번째"<< i/k <<endl;

             }

             catch(int e) { //catch블럭은try블럭에서발생한에러처리를실제로수행한다.

                           cout<< e <<" : 에러" <<endl;

             }

            

             cout<< ""<<endl;

 

}

출력내용

begin

첫번째:2

0 : 에러

 이렇게 하면 후 예외 처리에 관한 코드에서는 try 블록 외부에 신경을 쓸 필요가 없어진다.

예외는 반드시 try블럭 안에서만 발생한다. 또한 try에서 발생한 예외는 단지 throw로 던지기만 하면, catch블럭이 받는다. 즉 일관되게 catch에서 처리하는 것이다.

 

catch문에서 주의할 것!

 --throw k 에서 k의 변수타입과 catch에서 받은 인수의 타입이 서로 같아야한다.

Ex)

try{

int k=0;

throw k

}catch(int e) { } <- 에러나지않는다.

 

try{

int k=0;

throw k

}catch(char e) { } <- 에러!!

 

에러가 발생한 이유는 throw를 보냈는데 그 trhow를 받을 catch문이 없다는 내용이다.

 

 

catch문는 오버로딩가능하기에 여러개 선언가능하고 throw의 타입에 따라 맞는 catch문을 호출한다.

             try{

             }

             catch(char e) { //catch블럭은try블럭에서발생한에러처리를실제로수행한다.

             }

             catch(int e) { //catch블럭은try블럭에서발생한에러처리를실제로수행한다.

             }

            

 

catch(...) if문의 else와 같이 throw가 보내는 타입을 받는 catch가 없을 때는 catch(..)가 생행된다.

 

             try{

                           throw "에러발생!" ;

             }

             catch(char e) { //catch블럭은try블럭에서발생한에러처리를실제로수행한다.

             }

             catch(int e) { //catch블럭은try블럭에서발생한에러처리를실제로수행한다.

             }

             catch(...)

             {

               cout<<"try에서보내는throw는문자열이므로catchchar *형으로받아야한다.\n"

                   <<"그런데catch(char* e)가없기때문에바로이곳catch(...)문이실행된다."<<endl;

             }

 

 

 

◇ throw의 전파

 함수에서 호출된  throw는 함수를 호출한 try문이 받게된다.

throw가 있는 함수는 try문안에서 호출되어야한다. 안그럼 에러가 난다.

 

int i=5, j=2, k=0;

 

 

void g(){

             cout<<"G()"<<endl;

             throw 'A';

}

void h(){

             try {

                           if(k==0) throw k;

                           cout<< i/k<<endl;

             }

             catch(int k)

             {

                           cout<<" nested catch block"<<endl;

                           throw; //main()try()로보내고그곳에선catch(int e)로보낸다.

             }

}

 

void main() {

 

             //이문장은try블럭안에포함되지않으므로. 예외처리를하지않는다는것을보장한다.

             cout<< "begin" <<endl;

 

             try{

             //          g(); //g에서throw는이곳try가받아알맞는캐치catch(char e)로보내다.

                           h(); //catch안의throw는이곳try가받아알맞는캐치catch(int e)로보낸다.

             }catch(char e)

             {

                           cout<<e <<" : Char"<<endl;

             }

             catch(int e)

             {

                           cout<< e<<" : int "<<endl;

             }

             catch(char* e)

             {

                           cout<< e<<endl;

             }

             catch(...)

             {

                           cout<< "그외"<<endl;

             }

             // g(); //try문 밖에서 throw가 있는 함수를 호출하면 에러가 난다.

             cout<< "End"<<endl;

 

}

진화된 예러 처리 클래스

 -주의할건 클래스의 소멸자 호출되는 시점이다.

#include <iostream>

#include <stdio.h>

using namespace std;

 

//예외처리시정보를받는클래스 예외내용과 throw의 호출된 줄번호를 저장해준다.

class CException

{

             char m_name[80];

             int                       m_line;

public:

             CException(char* n,int Line)

             {

                                        strcpy(m_name, n);

                                        m_line =Line;

             }

             ~CException()

             {

                           printf("CException()소멸자호출\n");

             }

             char* GetName(){return m_name;}

             int                       GetLine(){return m_line;}

 

};

 

void main() {

             try          {

                           cout<<" 예외처리하는클래스연습"    <<endl;

                           throw CException("main()",__LINE__);

                           cout<< "throw의해의해실행되지않는다."<<endl;

             }

             catch(CException& e)

             {

                           cout<<"Excepton "<<e.GetName()

                                                     <<"at line " <<e.GetLine()<<endl;

             }

 

}

 

try문이 throw를 호출하게되면 try문안에서 호출된 클래스객체는 소멸자를 호출하게된다.

하지만 throw를 보낼 땐 복사를 하게 되고 그 정보가 그대로 남아있기 때문에 catch문에서 그대로 쓸 수 있게 된다. 즉 복사 생성자가 호출되고 있다.

 

출처: "게임개발자를 위한 C++ "