멤버 생성자 및 소멸자 호출 순서


121

오 C ++ 전문가, 당신의 지혜를 구합니다. 나에게 표준을 말하고 C ++가 다음 프로그램을 보장하는지 알려주십시오.

#include <iostream>
using namespace std;

struct A
{
    A() { cout << "A::A" << endl; }
    ~A() { cout << "A::~" << endl; }
};

struct B
{
    B() { cout << "B::B" << endl; }
    ~B() { cout << "B::~" << endl; }
};

struct C
{
    C() { cout << "C::C" << endl; }
    ~C() { cout << "C::~" << endl; }
};

struct Aggregate
{
    A a;
    B b;
    C c;
};

int main()
{
    Aggregate a;
    return 0;
}

항상 생산할 것입니다

A::A
B::B
C::C
C::~
B::~
A::~

즉, 멤버는 선언 순서에 따라 초기화되고 역순으로 소멸되는 것이 보장됩니까?


8
이것은 클래스가 커지고 불안정해질 때 미묘한 버그의 합리적으로 일반적인 원인입니다. 50 개의 데이터 멤버가 있고 생성자 이니셜 라이저 목록에서 많은 멤버가 초기화되면 생성 순서가 이니셜 라이저 목록의 순서라고 가정하기 쉽습니다. 결국 코드 작성자는 목록을 신중하게 주문했습니다 ... 그렇지 않습니까?
Permaquid 2010

답변:


140

즉, 멤버는 선언 순서에 따라 초기화되고 역순으로 소멸되는 것이 보장됩니까?

둘 다 예. 12.6.2 참조

6 초기화는 다음 순서로 진행됩니다.

  • 첫째, 아래에서 설명하는 가장 많이 파생 된 클래스의 생성자에 대해서만 가상 기본 클래스는 기본 클래스의 방향성 비순환 그래프의 깊이 우선 왼쪽에서 오른쪽 순회에 나타나는 순서대로 초기화됩니다. -to-right”는 파생 된 클래스 base-specifier-list에서 기본 클래스 이름이 나타나는 순서입니다.

  • 그런 다음 직접 기본 클래스는 기본 지정자 목록에 표시되는 선언 순서대로 초기화됩니다 (mem-initializer의 순서에 관계없이).

  • 그런 다음 비 정적 데이터 멤버는 클래스 정의에서 선언 된 순서대로 초기화됩니다 (다시 mem-initializer의 순서에 관계없이).

  • 마지막으로 생성자 본문의 복합 문이 실행됩니다. [참고 : 선언 순서는 기본 및 멤버 하위 개체가 초기화의 역순으로 삭제되도록해야합니다. —end note]


2
내가 정확히 기억한다면, 둘 다 맞아요 ... 스택으로 생각하세요. 처음으로 밀고 마지막으로 터졌습니다. 따라서 첫 번째 인스턴스를 인스턴스화 할 때 스택 순서대로 메모리로 푸시됩니다. 그런 다음 두 번째는 밀고 세 번째는 두 번째로 밀려납니다. 그런 다음 인스턴스를 제거 할 때 프로그램은 제거 할 첫 번째 인스턴스와 푸시 된 마지막 인스턴스를 찾습니다. 하지만이 방법으로 설명하는 것이 잘못되었을 수 있지만 C / C ++ 및 ASM을 할 때 배운 방법입니다.
Will Marcouiller 2010

29

예, 그렇습니다 (비 정적 멤버입니다). 초기화 (구성)에 대해서는 12.6.2 / 5를 참조하고 파괴에 대해서는 12.4 / 6을 참조하십시오.


10

예, 표준은 객체가 생성 된 역순으로 파괴되도록 보장합니다. 그 이유는 한 개체가 다른 개체를 사용할 수 있으므로 이에 의존하기 때문입니다. 치다:

struct A { };

struct B {
 A &a;
 B(A& a) : a(a) { }
};

int main() {
    A a;
    B b(a);
}

경우 a이전에 소멸했다 bb잘못된 멤버 참조를 개최한다. 생성 된 역순으로 개체를 파괴함으로써 올바른 파괴를 보장합니다.


이 규칙이 스코프 멤버의 폐기 순서에도 적용된다는 사실을 실제로 고려하지 않았습니다!
yano

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.