[C++] 항목 8: 예외가 소멸자를 떠나지 못하도록 붙들어 놓자!

업데이트:     Updated:

카테고리:

태그:

이 글은 아래의 책을 자세히 정리한 후, 정리한 글을 GPT에게 요약을 요청하여 작성되었습니다.
이펙티브 C++ 제3판, 스콧 마이어스 저자, 곽용재 번역

📦 2. 생성자, 소멸자 및 대입 연산자

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

1. 소멸자에서 예외 발생?

class Widget {
public:
    ~Widget() {
        ... // ❌ 이 안에서 예외 발생
    }
};

void doSomething() {
    vector<Widget> v;
    ...
} // 여기서 v 자동 소멸
  • vector<Widget>이 소멸되면서 내부 Widget 객체들도 파괴됨
  • 이때 소멸자에서 예외가 발생하면? → 정의되지 않은 동작(UB) 발생 가능성

예외가 떠나가며 다른 예외와 충돌하면? → C++ 런타임은 std::terminate() 호출, 즉 프로그램 종료


2. 예시: DB 연결 클래스

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

class DBConn {
public:
    ~DBConn() {
        db.close(); // ❌ 이게 예외를 던지면 위험
    }

private:
    DBConnection db;
};

이때 DBConn의 소멸자에서 db.close()가 예외를 던지면?

  • 예외를 처리하지 않으면 → terminate()
  • 예외를 삼키지 않고 밖으로 넘기면 → terminate()
  • 둘 다 위험한 상황

✅ 안전한 방식으로 변경

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

    ~DBConn() {
        if (!closed) {
            try {
                db.close(); // ✅ 예외 포착
            } catch (...) {
                // 로그만 남기고 예외 삼킴 or 종료
                ...
            }
        }
    }

private:
    DBConnection db;
    bool closed = false;
};
  • close()일반 함수로 분리
  • 사용자가 명시적으로 자원 해제를 할 수 있도록 설계
  • 소멸자에서는 예외를 삼키거나 로그 처리만

📌 중요한 이유는?

예외는 반드시 “사용자가 처리할 수 있는 곳”에서 발생해야 한다.

  • 소멸자는 그런 곳이 아니다.
  • 소멸자에서 예외가 발생하면 처리할 방법이 없다.
  • 따라서 예외가 발생할 수 있는 연산은 일반 함수로 제공해야 한다.

🧐 정리

  1. 소멸자에서는 예외가 밖으로 던져지면 안 된다.

    • 예외를 던질 수 있는 함수 호출 시엔 반드시 try-catch로 감싸야 한다.
    • 그렇지 않으면 프로그램은 무조건 종료된다.
  2. 예외가 발생할 수 있는 연산은 일반 함수로 제공하자.

    • 예외가 발생할 여지를 소멸자에 남겨두지 말자.
    • 사용자가 직접 close() 같은 함수로 자원을 해제하고, 예외에 대응할 수 있도록 해야 한다.
  3. 예외를 삼키든, 종료하든, 소멸자 내부에서는 반드시 예외를 잡아라!

Cpp 카테고리 내 다른 글 보러가기

댓글남기기