1

J'ai écrit un programme simple pour en savoir plus sur l'ordre de création et de destruction des objets en C++ (en utilisant Visual Studio 2015). Ici, il est:Ordre de création et de destruction d'objets en C++

#include <iostream> 
#include <string> 

using namespace std; 

class A 
{ 
public: 
    A(string name) 
     : name(name) 
    { 
     cout << "A(" << name << ")::constructor()" << endl; 
    } 
    ~A() 
    { 
     cout << "A(" << name << ")::destructor()" << endl; 
    } 
private: 
    string name; 
}; 

class C 
{ 
public: 
    C(string name, A a) 
     : name(name), a(a) 
    { 
     cout << "C(" << name << ")::constructor()" << endl; 
    } 
    ~C() 
    { 
     cout << "C(" << name << ")::destructor()" << endl; 
    } 
private: 
    string name; 
    A a; 
}; 

class B 
{ 
public: 
    B(string name) 
     : name(name) 
    { 
     cout << "B(" << name << ")::constructor()" << endl; 
    } 
    ~B() 
    { 
     cout << "B(" << name << ")::destructor()" << endl; 
    } 
private: 
    string name; 
    A a1{"a1"}; 
    A a2{"a2"}; 
    C c1{"c1", a1}; 
    A a3{"a3"}; 
}; 

int main() 
{ 
    B b("b1"); 
    return 0; 
} 

La sortie m'a surpris un peu (les a1 s):

A(a1)::constructor() 
A(a2)::constructor() 
C(c1)::constructor() 
A(a1)::destructor() 
A(a3)::constructor() 
B(b1)::constructor() 
B(b1)::destructor() 
A(a3)::destructor() 
C(c1)::destructor() 
A(a1)::destructor() 
A(a2)::destructor() 
A(a1)::destructor() 

Pour en savoir plus sur ce qui se passait, j'ai ajouté des informations sur les instances d'objets:

A(string name) 
     : name(name) 
    { 
     cout << "A(" << name << ")::constructor(), this = " << this << endl; 
    } 
    ~A() 
    { 
     cout << "A(" << name << ")::destructor(), this = " << this << endl; 
    } 

Le résultat était encore plus surprenant:

A(a1)::constructor(), this = 0039FB28 
A(a2)::constructor(), this = 0039FB44 
C(c1)::constructor() 
A(a1)::destructor(), this = 0039F8A8 
A(a3)::constructor(), this = 0039FB98 
B(b1)::constructor() 
B(b1)::destructor() 
A(a3)::destructor(), this = 0039FB98 
C(c1)::destructor() 
A(a1)::destructor(), this = 0039FB7C 
A(a2)::destructor(), this = 0039FB44 
A(a1)::destructor(), this = 0039FB28 

A savoir, pourquoi le constructeur de est-il seulement appelé une fois et destructeur 3 fois? Je passe a par la valeur si évidemment au moins 1 objet temporaire est créé mais s'il vous plaît expliquez-moi quand et combien d'instancesA sont créés et détruits?

+5

Vous n'avez pas annoté la plupart des autres constructeurs de votre classe, vous ne voyez donc qu'une image partielle. –

+0

@KerrekSB Vous parlez de l'impression de 'this' valeurs pour les classes B et C?Ou quoi? – NPS

+0

Le compilateur ajoute des constructeurs par défaut que vous ne pouvez pas voir. – Galik

Répondre

5

Comme déjà noté dans les commentaires, les objets de type A sont également construits via copy-construction lorsque vous les passez en arguments par valeur. Pour voir cela, vous pouvez ajouter une copie-constructeur sur votre propre:

A(const A& other) 
: name(other.name) 
{ 
    cout << "A(" << name << ")::copy-constructor(), this = " << this << endl; 
} 

Exemple de sortie:

A(a1)::constructor(), this = 0xbff3512c 
A(a2)::constructor(), this = 0xbff35130 
A(a1)::copy-constructor(), this = 0xbff350e8 
A(a1)::copy-constructor(), this = 0xbff35138 
C(c1)::constructor() 
A(a1)::destructor(), this = 0xbff350e8 
A(a3)::constructor(), this = 0xbff3513c 
B(b1)::constructor() 
B(b1)::destructor() 
A(a3)::destructor(), this = 0xbff3513c 
C(c1)::destructor() 
A(a1)::destructor(), this = 0xbff35138 
A(a2)::destructor(), this = 0xbff35130 
A(a1)::destructor(), this = 0xbff3512c 

Try it online

Comme vous pouvez le voir, une copie-construction se produit lorsque vous passer a1 en tant que paramètre au constructeur de c1 et un second se produit lorsque ce constructeur initialise son membre a. La copie temporaire est immédiatement détruite pendant que le membre est détruit lorsque c est détruit.

Edit:
Here vous pouvez lire les règles exactes lors de la création d'un constructeur de copie.
Afin de ne pas créer un constructeur de copie par défaut, il ne suffit pas de fournir un constructeur défini par l'utilisateur, il doit être un constructeur copy/move.

Edit2:

extraites de la norme 14 C++ (12,8 copie et objets de classe en mouvement):

7 Si la définition de classe ne déclare pas explicitement un constructeur de copie, on est déclaré implicitement. Si la définition de classe déclare un constructeur de déplacement ou un opérateur d'affectation de déplacement, le constructeur de copie implicitement déclaré est défini comme supprimé; sinon, il est défini par défaut (8.4). Ce dernier cas est déconseillé si la classe a un opérateur d'affectation de copie déclaré par l'utilisateur ou un destructeur déclaré par l'utilisateur.