[More Effective C++] 항목 13
항목 13 : 발생한 예외는 참조자로 받아내자
- 이론상 포인터로 예외를 발생시키면 객체 복사 없이 전달이 이루어지므로 예외 받기가 가장 효율적이어야 한다.
- 다음처럼 프로그램 흐름이 떠나면 객체가 소멸되면 안된다.
- ex)
void SomeFunction() { exception ex; // 함수 유효범위가 끝나면 소멸 throw &ex; // 소멸되려는 객체 포인터를 예외로 발생 }
- 대안 : 힙 객체를 새로 만들어서 그 객체의 포인터로 예외 발생 시키자
- ex)
{ throw new exception; // operator new가 예외를 일으키지 않아야 유효하다 }
- 위의 대안의 문제 : catch문에 들어온 포인터를 삭제해야 하나?
- 힙에서 할당된 예외객체 메모리를 가리키는 주소라면 삭제해야 한다.
- 힙에 할당되지 않은 객체 -> 해제시 미정의 동작을 일으킨다.
- 하지만 힙객체인지 아닌지 알기란 불가능하다.
- 또 다른 문제 : C++ 언어 자체의 규약에 역행한다.
- bad_alloc : operator new가 메모리 요구를 만족시키지 못했을 때
- bad_cast : dynamic_cast가 실패했을 때
- bad_typeid : dynamic_cast를 널 포인터에 적용했을 때
- bad_exception : 바라지 않은 예외가 발생했을 때
- C++에서 기본적으로 제공되는 표준 예외들이다.
- 이 표준 예외는 객체에 대한 포인터가 아니라 객체이므로 포인터로 예외를 받을 시 이 예외들을 사용할 수 없다.
-
값에 의한 예외 받기는 늘 두번 복사되어야 한다.
- 공포의 슬라이스 문제 : 파생 클래스가 기본 클래스를 받는 catch문에 들어가면서 파생 클래스 부분에 추가된 데이터가 잘리는 현상
- 값에 의한 전달 시 발생 가능
- 참조자에 의한 예외받기는 앞의 두 가지 방법이 가지는 문제를 겪지 않는다!
- 단지 catch문에만 앰퍼샌드(&)를 추가하면 모든 게 유효하게 동작한다!