2009-11-23 7 views
11

Pour autant que je sache, un constructeur de copie est invoqué dans les cas suivants:C++ copie invocation constructeur

1) Pass by value 
2) Return by value 
3) When you create and initialize a new object with an existing object 

Voici le programme:

#include <iostream> 
using namespace std; 
class Example 
{ 
    public: 
     Example() 
     { 
      cout << "Default constructor called.\n"; 
     } 
     Example(const Example &ob1) 
     { 
      cout << "Copy constructor called.\n"; 
     } 
     Example& operator=(const Example &ob1) 
     { 
      cout << "Assignment operator called.\n"; 
      return *this; 
     } 
     ~Example() 
     { 
      cout<<"\nDtor invoked"<<endl; 
     } 
     int aa; 
}; 

Example funct() 
{ 
    Example ob2; 
    ob2.aa=100; 
    return ob2; 
} 



int main() 
{ 
    Example x; 
    cout << "Calling funct..\n"; 
    x = funct(); 
    return 0; 
} 

La sortie est:

Constructeur par défaut appelé.

Calling fonct ..

constructeur par défaut appelé.

Opérateur d'assignation appelé.

dtor invoqué

dtor invoqué

S'il vous plaît me corriger, IIRC la séquence d'appels doit se produire suivant:

1) Constructor de x est appelé

2) Constructeur de ob2 est appelé

3) La fonction renvoie et donc le constructeur de copie i s invoqué (pour copier OB2 pour la variable temporaire anonyme ie funct())

4) Destructeur de OB2 appelé

5) Affecter la variable temporaire sans nom x

6) Détruire la variable temporaire à-dire invoquer son destructor

7) Destroy x x Invoke-à-dire de la destructor

Mais alors pourquoi constructeur de copie n'est pas appelé et aussi seulement 2 appels à dtors sont là alors que j'attendre 3.

Je sais que le compilateur peut faire des optimisations, mais est-ce que ma compréhension est correcte?

Merci beaucoup :)

Cordialement

lali

+2

Voici un article intéressant sur ce sujet: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/ –

+1

Il n'y a pas de vraie question ici ... Vérifiez la documentation de votre compilateur , parce que Copy-const peut être optimisé (comme vous nous l'avez déjà dit) – jpinto3912

+0

Yup, le comportement est dû à l'optimisation de la valeur de retour, merci beaucoup de le signaler. Le programme se comporte comme prévu lorsqu'il est compilé avec -fno-elide-constructors sur gcc. Merci à UncleBens pour cela :) – ghayalcoder

Répondre

11

Un constructeur de copie pourrait ne pas être invoqué lorsque vous revenez en valeur. Certains compilateurs utilisent la fonction d'optimisation de la valeur de retour.

En savoir plus sur "Valeur de retour Optimisation"

+0

d'accord, tester en débogage sans optimisations ou créer un cas de test plus compliqué. – slurdge

+0

Le même comportement se manifeste même si l'optimisation n'est pas activée. – Alexandru

+3

GCC dispose d'une commande spéciale (-fno-elide-constructors) pour désactiver cette optimisation qui est par ailleurs toujours activée. – UncleBens

2

Quand vous faites x = fonct(); le compilateur remarque qu'il sera directement renvoyé et évite ainsi une construction inutile. C'est aussi pourquoi vous n'obtiendrez que deux appels de destructeur.Ceci est un exemple pourquoi parfois travailler avec "copier" n'est pas nécessairement une perte de performances.

+0

"une construction inutile".Le point ici est cependant que la norme permet spécifiquement cette optimisation particulière, même si le constructeur a des effets secondaires, et n'est donc pas vraiment "inutile". Le compilateur ne peut généralement pas éluder le code qui écrit la sortie dans 'cout', car la sortie d'un programme C++ est considérée comme significative, même si l'ensemble du programme est" inutile "dans le sens quotidien ;-) –

0

Dans votre exampe la structure est assez petite donc il est passé à travers un registre. Le code généré est similaire à Return value optimization. Construire un exemple plus compliqué, et vous verrez le comportement attendu.

4

La partie de la norme qui vous indique quand les compilateurs peuvent avoir des copies est 12.8/15. Il revient toujours au compilateur de savoir s'il doit effectivement effectuer l'élision. Il y a deux situations juridiques, ainsi que toute combinaison d'entre eux:

  • « dans une déclaration de retour dans une fonction avec un type de retour de classe, lorsque l'expression est le nom d'un objet automatique non volatile avec le même CV -un type non qualifié comme type de retour de la fonction "

  • " lorsqu'un objet de classe temporaire qui n'a pas été lié à une référence est copié dans un objet de classe avec le même type cv-non qualifié ".

La première est généralement appelée «optimisation de valeur de retour nommée», et c'est ce qui permet la sortie que vous voyez dans votre exemple. Ce dernier transforme en effet l'initialisation de la copie en initialisation directe, et pourrait par exemple se produire si votre code était Example x = Example();.

D'autres élisions de copie ne sont pas permises, sauf bien entendu que les règles usuelles s'appliquent. Donc, si le constructeur de copie a suivi dans, puis le code suivant doit appeler:

Example x; 
Example y = x; 

Mais si x était autrement utilisé, et le cctor avait pas d'effets secondaires, alors je pense qu'il pourrait être optimisé loin , comme tout autre code qui ne fait rien.

0

g ++ V4.4.1 dispose d'une option pour supprimer "elide" optimisations:

 

[email protected]$ g++ -fno-elide-constructors Example.cpp -o Example 

[email protected]$ ./Example 

Default constructor called. 
Calling funct.. 
Default constructor called. 

Copy constructor called. 

Dtor invoked 
Assignment operator called. 

Dtor invoked 

Dtor invoked 

Comme vous pouvez le voir le constructeur de copie est maintenant appelé!

Questions connexes