본문 바로가기

프로그래밍/C/C++

try catch 문에 대한 고찰


#ads_1

#include <iostream>

using namespace std;

class Exception{
private:
     int ErrorCode;

public:
     Exception(int ae) : ErrorCode(ae) {
         cout << "생성자" << endl;
     }
     Exception(Exception &e){
         int ErrorCode = e.ErrorCode;
         cout << "복사생성자" << endl;
     }
     ~Exception(){
         cout << "소멸자" << endl;
     }
     int GetErrorCode() { return ErrorCode; }
     void ReportError() {
          switch (ErrorCode) {
          case 1:
              puts("메모리가 부족합니다.");
              break;
          case 2:
              puts("연산 범위를 초과했습니다.");
              break;
          case 3:
              puts("하드 디스크가 가득 찼습니다.");
              break;
          }
     }
};

void Calc(){
     if (true/*에러 발생*/) throw Exception(1);
}

void main(){
     try {
          Calc();
          puts("작업을 완료했습니다.");
     }
     catch(Exception &e) {
          printf("에러 코드 = %d => ",e.GetErrorCode());
          e.ReportError();

}

}


위 소스에서 catch구문에 throw 에서 던진 Exception 객체를 &e 형태로 참조가 가능하다.

throw에서 catch 문으로 오는 순간 Calc() 함수에서 빠져나올텐데 어째서 레퍼런스 형태로 참조가 가능할까란 궁금증이 생겼다.

단계적 디버깅과 여러 자료를 검색해 본 결과

throw Exception(1) 하는 순간 새로운 Exception 객체가 복사본으로 생성되고 원본 Exception 객체는 해제되어 버린다. (이때 스택 되감기가 실행된다.)

복사된 Exception 은 함수호출에 사용한 스택공간과는 별개의 공간에 생성되며 catch에서는 이 복사된 객체를 참조하게 된다.

원본은 이미 사라졌지만 복사본은 살아있기 때문에 레퍼런스형 참조가 가능한것이다.

예외가 발생했을때 이런 복잡한 과정을 거치기 때문에 성능이 중요할 경우엔 try catch 로 예외처리하는 건 바람직하지 않다.

처리비용이 아주 비싸기 때문인다.

또한 예외전에 malloc등으로 동적메모리를 할당했을때 예외가 발생하면 free할 수 있는 기회가 없다.  이럴때는 try catch문이 적당하지 않고 if문으로 직접 처리해야 메모리 누수가 없다.


<논외정보>

함수의 원형에서의 throw

void func(int a, int d) throw()  //어떤 예외도 던지지 않는다
void func(int a, int d)  //임의의 예외가 던져질 수 있다.
void func(int a, int d) throw(char*, int)  //임의의 예외가 던져질 수 있다.  괄호안의 내용은 char*형과 int형의 예외가 던져질 수 있다고 알리는 주석의 의미가 된다.

#ads_1