Ordre des appels de constructeur et de destructeur de membre

121

Oh gourous du C ++, je recherche ta sagesse. Parlez-moi standard et dites-moi si C ++ garantit que le programme suivant:

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

produira toujours

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

En d'autres termes, les membres sont-ils garantis d'être initialisés par ordre de déclaration et détruits dans l'ordre inverse?

sbk
la source
8
C'est une cause raisonnablement courante de bogues subtils lorsque les classes sont devenues grandes et désagréables. Lorsque vous avez 50 membres de données, et que beaucoup d'entre eux sont initialisés dans la liste d'initialisation du constructeur, il peut être facile de supposer que l'ordre de construction est l'ordre dans la liste d'initialisation. Après tout, les auteurs de code ont soigneusement ordonné la liste ... n'est-ce pas?
Permaquid

Réponses:

140

En d'autres termes, les membres sont-ils garantis d'être initialisés par ordre de déclaration et détruits dans l'ordre inverse?

Oui aux deux. Voir 12.6.2

6 L' initialisation se déroule dans l'ordre suivant:

  • Premièrement, et uniquement pour le constructeur de la classe la plus dérivée comme décrit ci-dessous, les classes de base virtuelles doivent être initialisées dans l'ordre dans lequel elles apparaissent sur un parcours en profondeur de gauche à droite du graphe acyclique dirigé des classes de base, où «gauche -to-right »est l'ordre d'apparition des noms de classe de base dans la classe dérivée base-specifier-list.

  • Ensuite, les classes de base directes doivent être initialisées dans l'ordre des déclarations telles qu'elles apparaissent dans la liste des spécificateurs de base (quel que soit l'ordre des initialiseurs de mémoire).

  • Ensuite, les membres de données non statiques doivent être initialisés dans l'ordre dans lequel ils ont été déclarés dans la définition de classe (là encore quel que soit l'ordre des initialiseurs de mémoire).

  • Enfin, l'instruction composée du corps du constructeur est exécutée. [Remarque: l'ordre de déclaration est mandaté pour garantir que les sous-objets de base et membres sont détruits dans l'ordre inverse de l'initialisation. —End note]

dirkgently
la source
2
Si je me souviens bien, oui aux deux ... Pensez-y comme une pile. Première poussée, dernière apparition. Ainsi, lors de l'instanciation de votre première instance, elle est poussée en mémoire dans l'ordre d'une pile. Ensuite, le second est poussé, le troisième sur le second et ainsi de suite. Ensuite, lors de la destruction de vos instances, le programme recherchera la première à détruire, la dernière qui a été poussée. Mais je peux me tromper en expliquant cela de cette façon, mais c'est la façon dont je l'ai appris en faisant C / C ++ et ASM.
Will Marcouiller
29

Oui, ils le sont (c'est-à-dire des membres non statiques). Voir 12.6.2 / 5 pour l'initialisation (construction) et 12.4 / 6 pour la destruction.

Fourmi
la source
10

Oui, la norme garantit que les objets sont détruits dans l'ordre inverse de leur création. La raison en est qu'un objet peut en utiliser un autre, donc en dépendre. Considérer:

struct A { };

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

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

S'il adevait détruire avant, bil bcontiendrait une référence de membre non valide. En détruisant les objets dans l'ordre inverse dans lequel ils ont été créés, nous garantissons une destruction correcte.

Wilhelmtell
la source
Je n'ai jamais réellement considéré que cette règle s'applique également à l'ordre de destruction des membres de la portée!
yano
6

Oui et oui. L'ordre de destruction est toujours opposé à l'ordre de construction, pour les variables membres.

Chris Jester-Young
la source