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

C++ 가상 소멸자(Virtual Destructor) 완벽 이해하기

C++에서 기본(base) 클래스 포인터를 사용하여 파생(derived) 클래스 객체를 삭제할 때는 반드시 기본 클래스에 가상 소멸자(virtual destructor)를 정의해야 합니다.

가상 소멸자가 없으면 기본 클래스 포인터로 객체를 삭제하는 순간 파생 클래스의 소멸자가 호출되지 않아 메모리 누수(memory leak)나 리소스 해제 누락 같은 심각한 문제가 발생할 수 있습니다. 소멸자 앞에 virtual 키워드를 붙이면, 실제 객체 타입에 맞는 소멸자가 올바른 순서대로 호출됩니다.

예제 코드

#include<iostream>
using namespace std;
class b {
    public:
        b() {
            cout<<"Constructing base \n";
        }
        virtual ~b() {
            cout<<"Destructing base \n";
        }
};
class d: public b {
    public:
        d() {
            cout<<"Constructing derived \n";
        }
        ~d() {
            cout<<"Destructing derived \n";
        }
};
int main(void) {
    d *derived = new d();
    b *bptr = derived;
    delete bptr;
    return 0;
}

실행 결과

Constructing base
Constructing derived
Destructing derived
Destructing base

결과 분석

위 실행 결과에서 주목할 점은 소멸 순서입니다. bptr은 기본 클래스 b의 포인터이지만, 소멸자가 virtual로 선언되어 있기 때문에 다형성(polymorphism)에 따라 파생 클래스의 소멸자가 먼저 호출된 후 기본 클래스의 소멸자가 호출됩니다.

만약 기본 클래스의 소멸자에 virtual이 붙어 있지 않았다면 delete bptr; 실행 시 Destructing base만 출력되고 파생 클래스의 소멸자는 호출되지 않아, 파생 클래스에서 할당한 자원이 해제되지 않는 문제가 생깁니다.

정리

  • 클래스가 상속을 위해 설계되었다면 소멸자를 항상 virtual로 선언하는 것이 안전합니다.
  • 생성자는 기본 클래스부터 파생 클래스 순으로 호출되고, 소멸자는 그 반대 순서로 호출됩니다.
  • 다형적(polymorphic) 사용이 전혀 없는 클래스라면 가상 소멸자가 불필요한 vtable 오버헤드를 만들 수 있으므로 상황에 맞게 적용하면 됩니다.