본문 바로가기

C++/C, C++, STL

클래스 소멸자(Destructor)

이 문서의 내용

    소멸자(Destructor)란?

    소멸자는 객체가 정해진 스코프(Scope)를 벗어나거나 또는 명시적으로 delete delete[] 되었을 때 호출되는 멤버 함수입니다.

    소멸자는 클래스의 이름과 동일한 이름으로 선언되며 이때 이름 앞에 ~ 문자가 prefix로 추가됩니다.

    class Human
    {
    	char* name;
    	int age;
        
    	~Human()
    	{
    
    	}
    };
    코드 비고
    Line 6:9 ~Human() { } Human 클래스에 대한 소멸자, 즉 멤버 함수입니다.
    소멸자는 인자 그리고 반환 값을 정의하고 가질 수 없습니다.

    소멸자를 명시적으로 정의하지 않으면 컴파일 과정에서 디폴트 소멸자가 제공됩니다.

    일부 클래스의 경우 컴파일러가 제공하는 디폴트 소멸자로 충분하지만, 어떤 클래스의 경우 멤버 변수 등에 의해 참조되고 있는 인스턴스를 소거하는 과정이 필요합니다.

    class Human
    {
    	char* name;
    	int age;
    
    	Human(char* _name)
    	{
    		name = _name;
    	}
    
    	~Human()
    	{
    		delete[] name;
    	}
    };

    위 예시에서는 char* name 멤버 변수에 동적 할당된 메모리 공간을 소멸자에서 delete합니다.

    소멸자의 호출 시점

    소멸자가 호출되는 시점은 다시 말해 인스턴스에 대한 생명 주기-라이프 사이클(Life cycle)입니다.

    #include <iostream>
    #include <cstring>
    
    using namespace std;
    
    void test()
    {
        class Human
        {
            char* name;
            int age;
    
        public:
            Human(char* _name)
            {
                name = _name;
            }
    
            ~Human()
            {
                delete[] name;
                std::cout << "~Human destructor invoked" << std::endl;
            }
        };
    
        char* name = new char[100];
        strcpy(name, "foo");
        Human m = Human(name);
    }
    
    int main()
    {
        test();
    }
    코드 비고
    Line 26:27 char* name = new char[100] name 변수에 문자열을 동적 할당합니다.
    strcpy(name, "foo")
    Line 28 Human m = Human(name) Human 객체를 생성합니다. 곧 이어 Scope를 벗어나 객체가 소멸됩니다.

    단순 블록 범위에 존재하는 객체는 Stack 메모리에서 관리됩니다.

    Stack에서 관리되는 객체는 해당 Scope를 벗어나는 시점에 자동으로 소멸자가 호출됩니다.

    ~Human destructor invoked

    반면 동적 할당된 객체는 Heap 메모리에서 관리됩니다.

    #include <iostream>
    #include <cstring>
    
    using namespace std;
    
    void test()
    {
        class Human
        {
            char* name;
            int age;
    
        public:
            Human(char* _name)
            {
                name = _name;
            }
    
            ~Human()
            {
                delete[] name;
                std::cout << "~Human destructor invoked" << std::endl;
            }
        };
    
        char* name = new char[100];
        strcpy(name, "foo");
        Human* m = new Human(name);
    }
    
    int main()
    {
        test();
    }
    코드 비고
    Line 28 Human* m = new Human(name) Human 객체를 동적 할당하고 포인터에 초기화합니다.

    Heap에서 관리되는 객체는 일정한 Scope가 존재하지 않기 때문에 자동으로 소멸자가 호출되지 않습니다.

    따라서 동적 할당된 객체는 명시적으로 delete 또는 delete[]를 호출하여 메모리 누수를 방지합니다.

    Human* m = new Human(name);
    delete m;

    정리 및 복습

    • 소멸자(Destructor)는 객체가 일정한 Scope를 벗어나거나 delete 또는 delete[] 되었을 때 호출되는 멤버 함수입니다.
    • 소멸자의 이름은 클래스 이름과 동일하며 ~ 문자를 prefix로 추가합니다.
    • 소멸자는 인자리턴 값을 가질 수 없습니다.
    • Stack 메모리에서 관리되는 객체는 Scope를 벗어날 때 자동으로 소멸자가 호출됩니다.
    • Heap 메모리에서 관리되는 객체는 명시적으로 delete 또는 delete[]를 호출해야 합니다.