Reihenfolge der Aufrufe von Mitgliedskonstruktoren und Destruktoren

120

Oh C ++ Gurus, ich suche deine Weisheit. Sprechen Sie mit mir Standardese und sagen Sie mir, ob C ++ das folgende Programm garantiert:

#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;
}

wird immer produzieren

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

Mit anderen Worten, wird garantiert, dass Mitglieder in der Reihenfolge der Erklärung initialisiert und in umgekehrter Reihenfolge vernichtet werden?

sbk
quelle
8
Dies ist eine ziemlich häufige Ursache für subtile Fehler, wenn die Klassen groß und unweildy geworden sind. Wenn Sie 50 Datenelemente haben und viele davon in der Konstruktor-Initialisierungsliste initialisiert sind, kann es leicht sein, anzunehmen, dass die Reihenfolge der Konstruktion die Reihenfolge in der Initialisierungsliste ist. Immerhin haben die Code-Autoren die Liste sorgfältig bestellt ... oder?
Meerjungfrau

Antworten:

138

Mit anderen Worten, wird garantiert, dass Mitglieder in der Reihenfolge der Erklärung initialisiert und in umgekehrter Reihenfolge vernichtet werden?

Ja zu beiden. Siehe 12.6.2

6 Die Initialisierung erfolgt in der folgenden Reihenfolge:

  • Zunächst und nur für den Konstruktor der am meisten abgeleiteten Klasse, wie nachstehend beschrieben, müssen virtuelle Basisklassen in der Reihenfolge initialisiert werden, in der sie auf einer tiefen ersten Durchquerung des gerichteten azyklischen Graphen der Basisklassen von links nach rechts erscheinen, wobei „left -to-right ”ist die Reihenfolge des Auftretens der Basisklassennamen in der abgeleiteten Klasse base-specifier-list.

  • Dann werden direkte Basisklassen in der Reihenfolge der Deklaration initialisiert, wie sie in der Basis-Spezifizierer-Liste erscheinen (unabhängig von der Reihenfolge der Mem-Initialisierer).

  • Anschließend werden nicht statische Datenelemente in der Reihenfolge initialisiert, in der sie in der Klassendefinition deklariert wurden (wiederum unabhängig von der Reihenfolge der Mem-Initialisierer).

  • Schließlich wird die zusammengesetzte Anweisung des Konstruktorkörpers ausgeführt. [Hinweis: Die Deklarationsreihenfolge muss sicherstellen, dass Basis- und Mitgliedsunterobjekte in umgekehrter Reihenfolge der Initialisierung zerstört werden. - Endnote]

dirkgently
quelle
2
Wenn ich mich richtig erinnere, ja zu beiden ... Betrachten Sie es als einen Stapel. Zuerst gedrückt, zuletzt geknallt. Wenn Sie also Ihre erste Instanz instanziieren, wird sie in der Reihenfolge eines Stapels in den Speicher verschoben. Dann wird der zweite übergeschoben, der dritte über den zweiten und so weiter. Wenn Sie dann Ihre Instanzen zerstören, sucht das Programm nach dem ersten, der zerstört werden soll, dem letzten, der verschoben wurde. Aber ich könnte mich irren, wenn ich es so erkläre, aber so habe ich es gelernt, als ich C / C ++ und ASM gemacht habe.
Will Marcouiller
29

Ja, das sind sie (nicht statische Mitglieder). Siehe 12.6.2 / 5 für die Initialisierung (Konstruktion) und 12.4 / 6 für die Zerstörung.

Ameise
quelle
10

Ja, der Standard garantiert, dass Objekte in der umgekehrten Reihenfolge zerstört werden, in der sie erstellt wurden. Der Grund ist, dass ein Objekt ein anderes verwenden kann und daher davon abhängt. Erwägen:

struct A { };

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

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

Wenn avor zerstören waren bdann bwürde ein ungültiges Mitglied Referenz halten. Durch die Zerstörung der Objekte in umgekehrter Reihenfolge, in der sie erstellt wurden, garantieren wir die korrekte Zerstörung.

wilhelmtell
quelle
Ich habe nie gedacht, dass diese Regel auch für die Vernichtungsreihenfolge von Scope-Mitgliedern gilt!
Yano
6

Ja und ja. Die Reihenfolge der Zerstörung ist für Elementvariablen immer entgegengesetzt zur Reihenfolge der Konstruktion.

Chris Jester-Young
quelle