발생한 예외는 참조자로 받아내자
예외 객체가 전달되는 방식을 설정하는 방법은 3가지가 있다
1. 포인터
2. 값
3. 참조자
비록 이렇게 3가지라고 하나 예외는 무조건 참조자로 받아야만 한다. 그 이유를 살펴보자.
1. 포인터
void someFunction()
{
exception ex;
…
throw &ex; // ex 객체는 유효범위를 벗어나면 소멸됨
}
void doSomething()
{
try {
someFunction();
}
Catch(exception * ex) // 소멸된 예외 객체를 가리킴
…
}
}
만약 new로 할당하여 예외 객체를 던지게 되면 예외 객체의 소멸 문제가 남아 있으며, 해당 예외가 new로 할당한 것인지 아님 전역 객체인지를 구분할 수 있는 방법이 없음.
2. 값
l Slicing Problem (잘림)
class exception {
virtual const char * what() throw();
}
class runtime_error : public exception { … };
class validation_error : public exception { … };
void someFunction () {
…
throw validation_error();
}
void doSomething() {
try {
someFunction();
}
catch(exception ex) {
cerr << ex.what();
}
}
발생한 예외가 validation_error 타입이고, validation_error에서 가상함수 what을 재정의하였다고 해도, 호출되는 what은 기본클래스인 exception의 what이 된다.
3. 참조자
참조자에 의한 예외받기는 두 방법이 가지고 있는 문제를 겪지 않는다. “포인터에 의한 예외받기”와 달리, 객체 삭제에 대한 고민도 할 필요 없고, C++ 표준 예외를 처리하는 데에도 무리가 없슴. 그뿐 아니라, “값에 의한 예외받기”와 달리 슬라이스 문제도 없고 예외 객체는 한 번만 복사된다. (값에 의한 예외 받기는 두번 복사되는데 이에 대한 자세한 내용은 More Effective C++ 항목 12 참고)
참고 : More Effective C++ - 스캇 마이어스 저