공부/C++

생성자 및 소멸자 호출 스택

Fel.Forest 2025. 3. 9. 02:47

생성자

어떠한 객체가 생길때 호출 되는 함수

이때 변수 초기화같은 일들을 함

소멸자

어떠한 객체가 메모리에서 해제 될때 호출되는 함수

A 클래스 경우

코드

#include <iostream>

class A
{
    static int a_Count;
public:
    A()
    {
        a_Count++;
        num = a_Count;
        std::cout << num << "A생성자 호출\n";
    }

    ~A()
    {
        a_Count--;
        std::cout << num << "A소멸자 호출\n";
    }

private:
    int num = 0;
};

int A::a_Count = 0;

int main()
{
	A a;
}

예상 출력값:

더보기

1A생성자 호출
1A소멸자 호출

실제 출력값:

더보기

1A생성자 호출
1A소멸자 호출

뭐 이건 당연한 이야기 같으니까 패스

 

A클래스를 맴버변수로 가지는 B클래스 경우

코드

#include <iostream>

class A
{
    static int a_Count;
public:
    A()
    {
        a_Count++;
        num = a_Count;
        std::cout << num << "A생성자 호출\n";
    }

    ~A()
    {
        a_Count--;
        std::cout << num << "A소멸자 호출\n";
    }

private:
    int num = 0;
};

class B
{
    static int b_Count;
public:
    B()
    {
        b_Count++;
        num = b_Count;
        std::cout << num << "B 생성자 호출\n";
    }

    ~B()
    {
        b_Count--;
        std::cout << num << "B 소멸자 호출\n";
    }

    // 테스트용 원래 이렇게 하면 안됨 
private:
    A a;
    int num = 0;

};

int A::a_Count = 0;
int B::b_Count = 0;

int main()
{
	B b;
}

예상 출력값:

더보기

1B생성자 호출

1A생성자 호출

1A소멸자 호출

1B소멸자 호출

실제 출력값:

더보기

1A생성자 호출

1B생성자 호출

1B소멸자 호출

1A소멸자 호출

생각한거의 딱 반대였음 일단 b가 호출이 되니까 B() 부터 호출 되는줄 알았는데 C++에서는 일단 안의 변수 부터 호출한다

좀 더 수정해 보자

 

수정 코드

#include <iostream>

class A
{
    static int a_Count;
public:
    A() : num(++a_Count)
    {
        std::cout << num << "A 생성자 실행\n";
        std::cout << num << "A 생성자 호출\n";
    }

    ~A()
    {
        std::cout << num << "A 소멸자 실행\n";
        a_Count--;
        std::cout << num << "A 소멸자 호출\n";
    }

private:
    int num = 0;
};

class B
{
    static int b_Count;
public:
    B() : num(++b_Count)
    {
        std::cout << num << "B 생성자 실행\n";
        std::cout << num << "B 생성자 호출\n";
    }

    ~B()
    {
        std::cout << num << "B 소멸자 실행\n";
        b_Count--;
        std::cout << num << "B 소멸자 호출\n";
    }

    // 테스트용 원래 이렇게 하면 안됨 
private:
    A a;
    int num = 0;

};

int A::a_Count = 0;
int B::b_Count = 0;

int main()
{
    B b;
}

결과값

더보기

1A 생성자 실행
1A 생성자 호출
1B 생성자 실행
1B 생성자 호출
1B 소멸자 실행
1B 소멸자 호출
1A 소멸자 실행
1A 소멸자 호출

일단 중단점 찍어서 확인해 보니까

  1. 생성자 순서
    1. b가 생성되는 순간
    2. a가 초기화 되면서 A()를 먼저 호출함
    3. a 생성자가 끝나고 나서 b를 초기화 하기 위해 B()를 호출함
  2. 소멸자
    1. b가 해제되는 순간
    2. 일단 ~B()를 호출
    3. 끝나고 나서 a를 해제 시키려고 ~A() 호출

결론 : 어떠한 클래스의 맴버변수를 클래스를 가지면 생성자가 호출할때 맴버변수가 초기화가 되면서 맴버변수 생성자부터 호출함

 

A클래스를 부모로 가지는 C클래스 경우

코드

#include <iostream>


class A
{
    static int a_Count;
public:
    A() : num(++a_Count)
    {
        std::cout << num << "A 생성자 실행\n";
        std::cout << num << "A 생성자 호출\n";
    }

    ~A()
    {
        std::cout << num << "A 소멸자 호출\n";
        a_Count--;
        std::cout << num << "A 소멸자 호출\n";
    }

private:
    int num = 0;
};

class C : public A
{
    static int c_Count;
public:
    C() : num(++c_Count)
    {
        std::cout << num << "C 생성자 실행\n";
        std::cout << num << "C 생성자 호출\n";
    }

    ~C()
    {
        std::cout << num << "C 소멸자 실행\n";
        c_Count--;
        std::cout << num << "C 소멸자 호출\n";
    }
    
private:
    int num = 0;
};

int A::a_Count = 0;
int C::c_Count = 0;

int main()
{
	C c;
}

예상 출력값:

더보기

1C 생성자 실행

1C생성자 호출

1A 생성자 실행

1A생성자 호출

1A 소멸자 실행

1A소멸자 호출

1C 소멸자 실행

1C소멸자 호출

실제 출력값:

더보기

1A 생성자 실행
1A 생성자 호출
1C 생성자 실행
1C 생성자 호출
1C 소멸자 실행
1C 소멸자 호출
1A 소멸자 실행
1A 소멸자 호출

이것 또한 생각한거의 딱 반대였음 일단 c가 호출이 되니까 C() 부터 호출 되는줄 알았는데 C++에서는 코드상 보이지만 않을 뿐 자식 클래스 내부에 포함된 멤버변수처럼 동작함

중단점 찍어서 확인해본 결과

  1. 생성자 순서
    1. C클래스의 변수를 초기화 하려고 A클래스 생성자 호출
    2. A클래스 생성자 호출 후 C클래스 생성자 호출
  2. 소멸자 순서
    1. C클래스 소멸자 호출
    2. C클래스 소멸자 끝나기 전에 A클래스 소멸자 호출
    3. A클래스 소멸자 끝나고 나서 C클래스 소멸자가 끝남

결론 : 어떤 클래스를 상속받은 클래스는 부모 클래스를 맴버변수 취급을함, 자식 클래스가 생성자 호출을 하면 부모 클래스를 먼저 초기화 하려고 부모 클래스 생성자 부터 호출함