소멸자에서는 예외가 빠져나가게 하지 말 것

항목 8 : 소멸자에서는 예외가 빠져나가게 하지



class Widget {
public:
 ~Widget() {} 
 //소멸자에서 에러가 발생한다고 가정
 //c++ 은 예외를 넘기는 소멸자를 좋아하지 않는다
};

void DoSomething() {
 std::vector<Widget> v(10); 
 //벡터에 담겨진 클래스 객체를 반환할때 그 책임은 벡터에 있다.
 //만약 벡터의 객체가 소멸될 때 에러가 터진다면?? 
}



 소멸자 안에서 호출된 함수가 예외를 던질 가능성이 있다면

소멸자에서 모두 받아낸 후에 삼켜버리던지(try/catch )
프로그램을 끝내든지 해야 한다.(std::abort()) 

 - 예외를 일으키는 소멸자는 프로그램의 불완전 종료 혹은 미정의 동작의 위험을 내포하고 있기 때문이다.


class DBConnection {
public:
 static DBConnection create();
 void close(); //연결을 닫기, 이때 연결이 실패하면 에러 발생
};

class DBConn {
public:
 DBConn(DBConnection target) : db(target) {}
 ~DBConn() {
  db.close; //객체 소멸시 db 연결을 닫기, 에러가 발생한다면?
 }
private:
 DBConnection db;
 
};

void DoSomething2() {
 DBConn dbc(DBConnection::create()); 
 //DBConn 객체 생성과 소멸이 이루어지도록, 동시에 DBConnection 에 대한 생성과 소멸도 발생
}



소멸자 내 try/catch 문을 활용한다면


~DBConn() {
 try { db.close(); }
 catch (std::exception& e) {
  //close 실패 로그 작성 - 에러 알리기
  //std::abort(); - 프로그램 종료하는 방법도 존재
 }
}


 가능한 한 소멸자가 아닌 다른 함수에서 예외가 발생하도록 조치해 두어야 한다. 소멸자에서 발생하는 에러는 위험하기 때문.

아래는 연결해제의 권한을 1차적으로 프로그래머에게 제공하는 방식



class DBConn {
public:
 DBConn(DBConnection target) : db(target) {}

 void close() { 
  //public 으로 선언하여 프로그래머가 사용할 수 있도록
  //1차적인 연결해제의 권한은 프로그래머에게
  db.close();
  closed = true;
 }
 ~DBConn() { //예외는 소멸장가 아닌 다른 함수에서 비롯되어야 한다

  if (!closed) { //사용자가 연결을 안 닫았으면 여기서 닫기
   try {
    db.close();
   }
   catch (std::exception& e) {
    //close 실패 로그 작성 - 에러 알리기
    //std::abort(); - 프로그램 종료하는 방법도 존재
   }
  }
 }

private:
 DBConnection db;
 bool closed;
};

댓글

이 블로그의 인기 게시물

Unity - Dialogue 시스템을 구현할 때 유용한 무료 에셋

Unity - 메타 파일

Unity - 라이브러리 폴더