Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++ 예외 처리와 개체 파괴: 소멸자의 자동 호출 메커니즘

C++에서 소멸자(Destructor)는 개체가 소멸되어 시스템에 메모리를 반환할 때 호출됩니다. 클래스 내부에서 예외가 발생하면, catch 블록이 실행되기 전에 이미 생성된 개체들의 소멸자가 자동으로 호출됩니다. 이 과정을 스택 풀기(stack unwinding)라고 부르며, C++ 예외 처리의 핵심 동작 방식입니다.

핵심 동작 원리

예외가 던져지는 순간 프로그램은 현재 스코프를 벗어나면서, 그 시점까지 완전히 생성된 모든 지역 개체의 소멸자를 역순으로 호출합니다. 여기서 중요한 규칙이 하나 있습니다. 바로 생성자 안에서 예외가 발생한 개체는 생성이 완료된 것으로 간주되지 않으므로, 해당 클래스의 소멸자는 호출되지 않는다는 점입니다.

알고리즘

시작
    sample1 클래스를 선언한다.
        sample1의 생성자를 선언한다.
            "Construct an Object of sample1" 출력
        sample1의 소멸자를 선언한다.
            "Destruct an Object of sample1" 출력
    sample2 클래스를 선언한다.
        sample2의 생성자를 선언한다.
            정수형 변수 i를 선언하고 7로 초기화한다.
            "Construct an Object of sample2" 출력
            i를 throw 한다.
        sample2의 소멸자를 선언한다.
            "Destruct an Object of sample2" 출력
    try 블록:
        sample1 클래스의 개체 s1을 선언한다.
        sample2 클래스의 개체 s2를 선언한다.
    catch(int i):
        "Caught" 출력
        변수 i의 값을 출력
끝

예제 코드

#include <iostream>
using namespace std;

class Sample1 {
public:
    Sample1() {
        cout << "Construct an Object of sample1" << endl;
    }
    ~Sample1() {
        cout << "Destruct an Object of sample1" << endl;
    }
};

class Sample2 {
public:
    Sample2() {
        int i = 7;
        cout << "Construct an Object of sample2" << endl;
        throw i;
    }
    ~Sample2() {
        cout << "Destruct an Object of sample2" << endl;
    }
};

int main() {
    try {
        Sample1 s1;
        Sample2 s2;
    } catch(int i) {
        cout << "Caught " << i << endl;
    }
}

실행 결과

Construct an Object of sample1
Construct an Object of sample2
Destruct an Object of sample1
Caught 7

결과 분석

실행 결과에는 주목할 만한 두 가지 포인트가 있습니다.

  • s1(Sample1)의 소멸자는 호출됨: s2의 생성자에서 예외가 던져지는 시점에 s1은 이미 완전히 생성된 상태였습니다. 따라서 catch 블록으로 제어가 넘어가기 전에 스택 풀기 과정을 거치며 s1의 소멸자가 자동으로 호출되었습니다.
  • s2(Sample2)의 소멸자는 호출되지 않음: 생성자 내부에서 예외가 발생했기 때문에 s2의 개체 생성 자체가 완료되지 않았습니다. 그 결과 "Destruct an Object of sample2"는 출력되지 않으며, 이는 C++ 표준이 보장하는 동작입니다.

이처럼 C++의 예외 처리 메커니즘은 이미 생성된 개체만 책임지고 정리함으로써 리소스 누수를 방지합니다. 이러한 특성은 생성 시점에 자원을 획득하고 소멸 시점에 해제하는 RAII(Resource Acquisition Is Initialization) 패턴의 기반이 되며, 스마트 포인터 등 현대 C++의 자원 관리 기법 전반에 활용됩니다.