책 정리/Effective C++ 3rd

항목 8. 예외가 소멸자를 떠나지 못하도록 붙들어 놓자

ocean20 2019. 12. 17. 11:14

말그대로 예외 동작이 소멸자 내에서 종료되어야 함을 의미한다.

 

1. 소멸자가 호출되는경우

  (1) 정상적으로 객체가 종료되었을때

  (2) 예외처리 메커니즘에 의해 객체가 소멸될때

 

(2)와 같이 예외처리 메커니즘에 의해 객체가 소멸될때  예외가 발생한다면, terminate함수가 호출되어 프로그램이 종료된다. 따라서 try catch 예외를 소멸자내에서 묶어두어야 한다.

 

일반적으로 c++ 예외를 내보내는 소멸자를 좋아하지 않는다!!라고 생각하자.

 

 우선  코드를 봐보자.

class DBConnection {
public :
...
  static DBConnection create();
  void close();
};

class DBConn {
public :
...
  ~DBConn()
  {
  db.close();  //여기서 예외발생시 소멸자에서 예외가 나가도록 내버려둔다.
  }
  
private:
  DBConnection db;
};

위 코드에서 DBConn객체에 예외가 발생하여 ~DBConn()호출을 하였고, 여기서 또 예외발생시, 프로그램이 미정의 동작을 발생시킬것이다.

 

TIP). try catch 예외를 소멸자에 묶어보자.

 

해결방법 1. 프로그램을 바로 끝낸다.

DBConn::~DBConn()
{
  try{db.close();}
  catch(…){
  //close 호출이 실패했다는 로그를 작성합니다;
  std::abort();
  }
}


해결방법 2. 예외를 삼켜버린다. 

DBConn::~DBConn() 
{ 
  try { db.close(); } 
  catch(…){ 
  //close 호출이 실패했다는 로그를 작성합니다; 
  } 
}

 

위 경우는 예외를 삼킨 이후에도 프로그램의 정상동작이 보장되어야 빛을 볼것이다.

 

해결방법3. 문제 대처기회를 사용자에게 제공하자. 책임전가 해버리자.

따라서 예외 발생시 예외는 소멸자가 아닌 다른 함수에서 비롯되어야 한다.

예외를 일으키는 소멸자는 시한폭탄이다.!!!

class DBConn{
public :
  void close()
  {
    db.close();
    closed = true;
  }

  ~DBConn()
  {
    if(!closed)
      try{
      db.close();
      }
      catch(...){
      //close 호출이 실패했습니다. 로그작성
	  ...
  }

private:
  DBConnection db;
  bool closed;
};

 

이것만은 잊지 말자!

  1. 소멸자에서 예외를 묶어두자. 방법은 삼키던가 프로그램 강제종료시키던가

  2. 예외가 발생하는 함수는 보통의 함수여야 한다.(소멸자가 아닌 함수)