#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