Maison > Article > développement back-end > Pourquoi le constructeur de déplacement C 11 n'est-il pas appelé lorsqu'un objet temporaire est utilisé pour initialiser un autre objet ?
Description :
Lorsque vous travaillez avec la sémantique de déplacement en C 11, c'est possible pour rencontrer des scénarios dans lesquels le constructeur de déplacement est ignoré de manière inattendue en faveur du constructeur par défaut. Cet article explore ce problème, examine les raisons sous-jacentes et propose des solutions.
Problème :
Considérez la classe X suivante avec des constructeurs qui génèrent des messages :
<code class="cpp">class X { public: explicit X(char* c) { cout << "ctor" << endl; init(c); } X(X& lv) { cout << "copy" << endl; init(lv.c_); } X(X&& rv) { cout << "move" << endl; c_ = rv.c_; rv.c_ = nullptr; } const char* c() { return c_; } private: void init(char *c) { c_ = new char[strlen(c)+1]; strcpy(c_, c); } char* c_; };</code>
Dans l'exemple d'utilisation fourni ci-dessous, nous créons trois objets :
<code class="cpp">X x("test"); cout << x.c() << endl; X y(x); cout << y.c() << endl; X z( X("test") ); cout << z.c() << endl;</code>
Cependant, au lieu de la sortie attendue montrant le constructeur de déplacement appelé pour z, le constructeur par défaut est utilisé à la place.
Conformité à la norme :
Selon la norme C 11 (§12.8.32), la sémantique de déplacement doit être préférée à la sémantique de copie dans la mesure du possible. Ainsi, le constructeur de déplacement devrait effectivement être appelé pour z dans ce cas.
Explication du comportement :
Le comportement observé est dû à une optimisation du compilateur appelée copie élision. C 11 permet aux compilateurs d'omettre de copier/déplacer des objets dans certaines situations pour améliorer les performances. L'une de ces situations est celle où un objet temporaire serait copié/déplacé vers un objet avec le même type cv non qualifié.
Dans la dernière ligne de notre exemple de code, X("test") crée un X temporaire objet et il a le même type cv non qualifié que la cible (z). Par conséquent, le compilateur est autorisé à éliminer les constructeurs de copie et de déplacement, en construisant directement l'objet temporaire dans z sans invoquer aucun des constructeurs.
Solution :
Pour forcer le constructeur de déplacement à être appelé, nous pouvons utiliser std::move() pour indiquer explicitement que le déplacement doit avoir lieu :
<code class="cpp">X z( std::move(X("test")) );</code>
Avec cette modification, le résultat attendu est produit, confirmant l'implication du constructeur de déplacement.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!