본문 바로가기
C++

C++ 예외 처리

by 상레알 2009. 2. 18.
기본적인 예외 처리 메커니즘( try, catch, throw)

try - 예외 발생에 대한 검사 범위를 설정할 떄 사용된다. 즉 try 블록으로 쌓여진 범위는 예외 상황이 발생하였는지에 대한 검사 대상의 범위가 된다.

try{
/*예외 발생 예상지역 */
}

catch -
예외를 처리하는 코드 블록을 선언할 때 사용한다. try 블록내에서 발생한 예외 상황을 처리하는 코드가 존재하는 영역으로서, 그 형태가 마치 리턴 타입 없는 함수와 유사하다.

catch(처리되어야 할 예외의 종류){
                       /*   예외를 처리하는 코드가 존재할 위치 */
}

try와 catch

catch 블록은 항상 try 블록 뒤에 바로 이어서 등장해야 한다.  그래서 보통은 try와 catch를 하나의 문장으로 간주한다.

try{
  /* 예외 발생 예상 지역 */
}
catch(처리되어야할 예외의 종류){
   /*예외를 처리하는 코드가 존재할 위치 */
}

throw- 예외 상황이 발생하였음을 알릴 때 사용된다.

throw ex;   //ex를 가리켜 보통은 그냥 "예외" 라고 표현을 한다.

"throw 문에 의해 던져진 예외는, 예외를 감싸는 rty 블록 다음에 catch 블록에 의해 처리된다."

try {
     if(예외 상황 발생)
           throw   ex
}

catch(exception  ex){
       예외 상황 처리
}

"catch(int exception)" 
이는 int형 예외를 처리하겠다는 선언이다. 다시 말하면, 전달되는 예외를 int형 변수 exception 으로 받겟다는 선언이다. 
전달되는 예외와 이를 받아줄 변수의 자료형은 일치해야 한다.

예외처리 는 마치 함수의 인자 전달과 그 형태가 비슷하다. 실제로 catch블록은 함수와 유사하다. 에외가 전달되는 형식은 함수의 인자 전달과 그 형태가 동일할 뿐만 아니라, catch 블록 내에서 선언되는 변수들도 함수 내에 선언된 변수들과 마찬가지로 스택 공간에 할당이된다.

- 처리 되지 않은 예외 ( 즉 함수를 통해서 예외가 잇을경우를 말한다?-_-;? )는 전달된다는 것을 알았다.
이러한 것을 스택 unwinding(풀기)라고 한다.

ex) 
int main(void)
{
    try{
          fct();
}
catch(int ex){
cout<<" 예외: " <<ex<<endl;
}
return 0;
}

void fct1(){    fct2();    }
void fct2(){   fct3();    }
void fct3(){   throw 100;  }

위 예제를 보면 마지막에 호출된 fct3 함수 내에서는 예외를 발생시키고 있다. 그런대 fct3 함수 내에서 이 예외를 처리하지 않고 있다. 따라서  fct3 함수르 호출한 영역으로 예외가 전달된다..그리고fct3를 호출한 함수로....그래서 main 함수 영역까지 올라간다
이렇게 예외가 전달되는 과정이 함수의 스택이 풀리는 순서와 일치한다.
예외가 전달되면서 동시에 스택도 해체가 된다. 그래서 예외의 전달을 가리켜 스택 unwinding(풀기)라고 하는 것이다.  - 그림을 그려면 이해가 될것이다!!;

헤더파일 stdlib.h 에 선언되어 있는 abort 함수가 잇는대 에러 메시지를 출력하고 나서 프로그램 종료!
<stdlib.h>
예외가 발생햇는대 에러를 처리하지 못하면 abort 함수를 통해 에러메시지를 출력하고 나서 프로그램을 종료한다.
명시적으로  abort 함수를 적어 줄수 도 있다.

함수를 정의하는데 있어서 전달 될수 있는 예외의 종류를 명시해 줄 수 있다. 밑 함수 정의 처럼 말이다.
int fct(double d) throw (int )    // fct 함수는 int형 예외를 전달할 수 있다.

이 함수는 상황에 따라서 int형 예외가 전달될 수있음을 선언하고 있는것이다. 따라서 int형이 아닌
 다른 형의 예외가 발생할 경우, 헤더 파일 stdlib.h에 선언되어 있는 abort 함수가 호출되면서 프로그램은 종료하게 된다.!

전달될 수 있는 예외의 종류가 둘 이상이 될 경우에는
int fct(double d) thorw (int, double, char*)   -> 이렇게 선언하면 된다. 이 정의는 상황에 따라서 int형 double형, char* 형 예외가 전달될 수 있음을 선언하고 있다.  그이외의 예외가 전달될 경우 역시 abort함수가 호출된다.!!!


int fct(double d) throw ( )     자 이렇게 선언이 되어 있다면 어떤 의미를 지니게 될까?

예외의 종류를 명시하는 부분이 비어 있음을 알 수 있다. 즉 이 함수는 어떠한 예외도 전달하지 않는다는 것을 이야기한다. 만약에 예외가 전달된다면, abort 함수가 호출되면서 프로그램은 종료를 하게 된다!!

- 전달되는 예외를 명시 하지 않으면 어떠한 예외도 전달될 수 있다. 그럼에도 불구하고 이렇게 전달 되는 예외를 명시하는 이유는 정보의 전달이다.
예를 들어서 위에서 정의한 fct함수를 호출하는 코드를 작성해야 하는 프로그래머가 있다고 가정해 보자. 이 프로그래머는 함수의 내부를 들여 다 보지 않아도, 함수의 선언을 통해서 어떠한 예외가 전달되 수 있는지를 파악하는 것이 가능하다. 따라서 그에 따른 적절한    try ~catch 문을 선언하게 될것이다.


하나의 try 블록내에서 둘 이상의 서로 다른 예외(자료형이 서로 다른 예외)가 발생할 수 있는 상황도 존재하기 마련이다. 이러한경우는  catch 블록을 이어서 선언하는 것이 가능하다.

지금까지는 예외를 발생시키기 위해서 클래스를 정의하고 객체를 생성하엿다. 이러한 객체를 예외 객체라 하고 예외 객체를 위해 정의되는 클래스를 가리켜 예외 클래스 라한다.


[ 예외 상황을 나타내는 클래스의 설계  ]

예외를 발생시키기 위해서 클래스를 정의하고 객체를 생성하였다. 이러한 객체를 예외 객체라 하고 예외 객체를 위해 정의되는 클래스를 가리켜 예외 클래스라 한다.

객체를 예외로 사용하기 위해서는 예외 상황에 대한 정보를 잘 표현하는 클래스(예외 클래스)도 정의해야하고 객체이다 보니 전체 프로그램의 성능이 저하될 수도 있다는 것도 생각해 봐야 한다. 그럼에 도 불구하고 예외를 객체로 표현하는 이유는 무엇일까?  성능 (속도, 메모리) 이 중요시되는 프로그램을 구현한다고 가정해 보자. 그렇다면 예외를 객체로 표현하지 않는 것이 보다 낫지 않을까?

성능이 중요시되는 프로그램에서는 C++의 예외 처리 메커니즘 자체를 적용하지 말아야하낟. try~catch를 사용하게 되면, 컴파일 된 코드에 예외 검사 코드가 추가되고, 스택 unwinding을 위한 코드가 더불어 추가된다. 따라서 실행 파일의 크기는 조금 증가하게 되고, 속도 또한 저하된다.

오늘날의 프로그램은 대부분 속도보다는 가독성 및 유지 보수성에 중점을 두고 설계된다. 이는 하드웨어의 급속한발전에 힘 입은 결과라고도 볼 수 있다. 따라서 try~ catch를 기반으로 하는 예외처리를 적용하고자 한다면 가급적이면 예외 클래스를 디자인하는것이 좋다. 그래야 예외 상황에 대한 정보를 충분히 담아서 예외를 처리하는 영역에 전달할 수 있기 때문이다. 

예외를 나타내는 클래스를 디자인 할때는 예외 상황을 잘 표현할 수 있도록 정의되기만 하면 된다. 한가지 더 언급을 한다면, 깊은 복사를 하기 위한 복사 생성자 및 댕비 연산자의 정의가 필요하지 않도록 간결한 구조로 구성하는것이 좋다.

예외의 형태가 유사한 경우 예외 클래스를 상속하는 경우, 확장성에서 이점을 얻게 되는데(일반적인 상속의 이점이다),

catch 블록에 예외가 전달되는 형태를 보면 함수 오버로딩과 유사하다는 생각을 할수 있다!
그러나 함수 오버로딩과는 아주 큰 차이점이 하나 존재한다. 오버로딩도니 함수는 딱! 봐서 매개 변수가 일치하는 함수가 호출이 되지만  catch 블록은 딱! 봐서 결정되는것이 아니다. 순차적인 비교가 이루어지고 , 결정이 난다.

즉. 예외가 발생하면 제일 먼저 첫 번째 catch 블록을 본다. 그리고 예외를 전달받을 수 있는지 없는지를 결정한다. 전달받을 수 있으면 첫 번째 catch블록에 예외가 전달이 되고 끝이 난다.

'C++' 카테고리의 다른 글

use of class template requires template argument list ->컴파일 에러  (0) 2009.02.18
클래스 템플릿!  (0) 2009.02.18
함수 템플릿!!!  (0) 2009.02.17
임시 객체에 대하여....  (0) 2009.02.16
string 클래스 디자인  (0) 2009.02.16
oop 프로젝트 8단계 중...  (0) 2009.02.12
배열의 인덱스 연산자 오버로딩  (0) 2009.02.10
cout / cin / endl 에 대하여...  (0) 2009.02.10
단항 연산자의 오버로딩  (0) 2009.02.09
연산자 오버로딩  (0) 2009.02.06