일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- reference
- c++
- 루아
- 함수 객체
- effective stl
- 다형성
- resource management class
- 영화
- 반복자
- 예외
- 티스토리챌린지
- 참조자
- 게임
- 상속
- lua
- 오블완
- UE4
- virtual function
- 스마트 포인터
- 암시적 변환
- more effective c++
- Smart Pointer
- 메타테이블
- operator new
- 비교 함수 객체
- 언리얼
- exception
- implicit conversion
- Effective c++
- 영화 리뷰
Archives
- Today
- Total
스토리텔링 개발자
[More Effective C++] 11. 소멸자 예외 처리 본문
728x90
항목 11 : 소멸자에서는 예외가 탈출하지 못하게 하자
소멸자가 호출되는 상황
- 객체가 통상적인 조건에서 소멸되었을 때
- 지역변수 객체가 유효범위(scope)를 벗어날 때
- 객체가 직접 삭제(delete)될 때
- 예외 처리 매커니즘에 의해 객체가 소멸되었을 때
- 예외 전파(exception propagation) 과정의 일부분으로 스택 되감기가 진행될 때
- 즉, 소멸자가 호출되었을 때 예외가 발생된 상태인지 아닌지 알 방도가 없다.
- 실은 이제는 std::uncaught_exception을 통해서 예외가 스택 되감기(unwinding) 중인지 알아낼 수 있다.
예외가 소멸자를 빠져나가면 안되는 이유 1
- 소멸자 내부에서 예외 발생 상태인지 구별할 방법이 없다.
- 어떤 상황이든 예외가 발생된 상태라고 가정하고 소멸자를 방어적으로 작성하도록 한다.
- 만일 예외가 중첩되면 C++이 terminate를 호출하여 프로그램을 강제 종료해 버린다.
class Session
{
public:
Session();
~Session();
...
private:
static void logCreation(Session* objAddr);
static void logDestruction(Session* objAddr);
};
Session::~Session()
{
logDestruction(this); // 만약 여기서 예외가 발생한다면?
// 여기서 try / catch로 처리하지 않기 때문에 예외는 빠져나간다.
// 하지만 이 객체의 소멸자가 호출된 원래 이유가 또 다른 예외 때문이었다면?
// C++는 바로 terminate를 호출하고, 프로그램이 죽어버린다.
}
- try-catch 블록으로 소멸자에서 발생한 예외가 빠져나가지 않게 한다.
Session::~Session()
{
try
{
logDestruction(this);
}
catch( ... )
{
cerr << "Unable to log destruction of Session object "
<< "at address "
<< this
<< ".\n";
// 하지만...
// operator<<에서 예외가 발생한다면?
// 역시나 예외가 소멸자가 빠져나간다..
}
}
- try-catch 문을 또 안에? 구조가 너무 복잡해진다..
- 그러니 그냥 예외가 발생하면 로깅 처리를 하지 않도록 한다.
Session::~Session()
{
try
{
logDestruction(this);
}
catch( ... ) {} // 아무 일도 하지 않는다.
}
- 아무 일도 하지 않는 것이 아니라..
- 실은 logDestruction에서 발생한 예외가 밖으로 전파되지 않도록 잡아두는 역할이다.
- 예외가 소멸자를 못 빠져나가게 한다는 목적에는 이것으로 충분하다.
예외가 소멸자를 빠져나가면 안되는 이유 2
- 소멸자에서 발생된 예외가 소멸자에서 처리되지 않으면
- 소멸자는 실행이 끝나지 않은 상태로 남게 된다.
Session::Session()
{
logCreation(this);
startTransaction();
}
Session::~Session()
{
logDestruction(this); // 여기서 예외가 발생하고, 빠져나가면...
endTransaction(); // endTransaction은 영원히 호출되지 않는 상황이!!
}
- endTransaction과 logDestruction의 순서를 바꾼다?
- endTransaction에서도 예외가 발생할 수 있으므로
- transaction 정리가 마무리되지 않을 수 있는 건 마찬가지이다.
정리
- 예외가 전파되던 중 소멸자가 불렸고, 그 와중에 소멸자가 다른 예외를 던지면 프로그램이 멈춘다.
- 소멸자가 예외를 토해내면 예외가 중첩되어 terminate 함수가 호출되기 때문이다.
- 그러므로 소멸자 안에서 예외를 소화해 주어야 한다.
- 소멸자의 동작이 완전히 끝나지 않는다.
- 소멸자에서 예외가 빠져나가면 그 소멸자는 실행이 끝나지 않은 상태로 남는다.
- 그러므로 소멸자 안에서 예외를 처리하고 소멸자가 해야 할 일을 온전히 마무리 지어주어야 한다.
참조
728x90
'개발 > More Effective C++' 카테고리의 다른 글
[More Effective C++] 13. catch 매개변수는 참조자 (0) | 2024.08.16 |
---|---|
[More Effective C++] 12. 예외 전달 vs 함수 매개변수 전달 (0) | 2024.08.14 |
[More Effective C++] 10. 생성자 예외 처리 (0) | 2024.08.12 |
[More Effective C++] 9. 자원 관리 객체(RAII) (0) | 2024.08.09 |
[More Effective C++] 8. new / delete 연산자와 operator new / delete (0) | 2024.08.08 |
Comments