[C++] 항목 8: 예외가 소멸자를 떠나지 못하도록 붙들어 놓자!
카테고리: Cpp
태그: Cpp
이 글은 아래의 책을 자세히 정리한 후, 정리한 글을 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()
를 일반 함수로 분리- 사용자가 명시적으로 자원 해제를 할 수 있도록 설계
- 소멸자에서는 예외를 삼키거나 로그 처리만
📌 중요한 이유는?
예외는 반드시 “사용자가 처리할 수 있는 곳”에서 발생해야 한다.
- 소멸자는 그런 곳이 아니다.
- 소멸자에서 예외가 발생하면 처리할 방법이 없다.
- 따라서 예외가 발생할 수 있는 연산은 일반 함수로 제공해야 한다.
🧐 정리
-
소멸자에서는 예외가 밖으로 던져지면 안 된다.
- 예외를 던질 수 있는 함수 호출 시엔 반드시
try-catch
로 감싸야 한다. - 그렇지 않으면 프로그램은 무조건 종료된다.
- 예외를 던질 수 있는 함수 호출 시엔 반드시
-
예외가 발생할 수 있는 연산은 일반 함수로 제공하자.
- 예외가 발생할 여지를 소멸자에 남겨두지 말자.
- 사용자가 직접
close()
같은 함수로 자원을 해제하고, 예외에 대응할 수 있도록 해야 한다.
-
예외를 삼키든, 종료하든, 소멸자 내부에서는 반드시 예외를 잡아라!
댓글남기기