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?


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]


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.


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.


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.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.