1. C++은 소멸자에서 나오는 예외를 싫어한다
class Widget{
public:
...
~Widget(){...}
};
void doSomething()
{
std::vector<Widget> v;
...
};
vector v가 소멸되는 경우에 차례대로 요소의 소멸자가 호출된다. 첫 번째 요소에서 예외가 발생한다 하더라도 나머지 요소들 소멸자를 호출하기 위해 두 번째 요소의 소멸자를 호출하게 된다. 이 때 예외가 또 발생한다면 C++ 입장에서 감당하기 버거우며 미정의 동작 가능성을 내포하게 된다.
2. 데이터베이스 연결을 통해 예외 파악하기
class DBConnection{
public:
//...
static DBConnection Create();
void Close();
};
class DBConn{
public :
~DBConn()
{
db.close();
}
private :
DBConnection db;
};
// ...
{
DBConn dbc(DBConnection::Create());
}
문제는 dbc가 블록을 빠져 나간 경우 그 소멸자에서 예외가 나가도록 내버려두는 점이다. 예외를 던지는 소멸자는 곧 '걱정거리'를 의미한다.
3. 걱정거리를 피하는 방법
- close에서 예외가 발생하면 프로그램을 바로 끝낸다.
- close를 호출한 곳에서 일어난 예외를 삼켜 버린다.
둘 다 좋은 방법은 아니다. 예외를 던진 이후에 사용자가 조치를 취할 방법이 없기 때문이다.
class DBConn{
public:
// ...
void Close()
{
db.close();
closed =true;
}
~DBConn()
{
if(!closed)
try{
db.close();
}
catch(...){
// close 호출 실패 로그 작성
}
}
private:
DBConnection db;
bool closed;
};
이 코드에서 중요한 점은 그 예외는 소멸자가 아닌 다른 함수에서 비롯된 것이라는 점이다. 예외를 일으키는 소멸자는 시한포탄이나 마찬가지라서 프로그램의 불완전 종료 혹은 미정의 동작의 위험을 내포하고 있기 때문이다.
위 코드에서는 사용자에게 예외를 대처할 기회를 한 번 더 얻게된다. (Close()에서 에러가 터져도 소멸자에서 한 번 더 닫아준다.)
이것만은 잊지 말자!
- 소멸자에서는 예외가 빠져나가면 안됩니다. 만약 소멸자 안에서 호출된 함수가 예외를 던질 가능성이 있다면, 어떤 예외이든지 소멸자에서 모두 받아낸 후에 삼켜버리든지 프로그램을 끝내든지 해야 합니다.
- 어떤 클래스의 연산이 진행되다가 던진 예외에 대해 사용자가 반응해야 할 필요가 있다면, 해당 연산을 제공하는 함수는 반드시 보통의 함수(즉, 소멸자가 아닌 함수)이어야 합니다.
'C++ > Effective C++' 카테고리의 다른 글
[Effective C++] 10. 대입 연산자는 *this의 참조자를 반환하게 하자 (0) | 2020.07.28 |
---|---|
[Effective C++] 9. 객체 생성 및 소멸 과정 중에는 절대로 가상 함수를 호출하지 말자 (0) | 2020.07.28 |
[Effective C++] 7. 다형성을 가진 기본 클래스에서는 소멸자를 반드시 가상 소멸자로 선언하자 (0) | 2020.07.27 |
[Effectivce C++] 6. 컴파일러가 만들어낸 함수가 필요 없으면 확실히 이들의 사용을 금해 버리자 (0) | 2020.07.27 |
[Effectivce C++] 5. C++가 은근슬쩍 만들어 호출해 버리는 함수들에 촉각을 세우자 (0) | 2020.07.27 |