J'ai testé la fonction de déplacement de c ++ 11, mais je ne suis pas devenue efficace. Qui peut me dire pourquoi? Merci. Le code est comme suit:
class Base {
public:
Base() { cout << "Base" << endl;}
~Base() { cout << "~Base" << endl;}
Base(const Base& base) { cout << "Copy" << endl; }
Base& operator=(const Base& base) {cout << "operator=" << endl;}
Base(Base&& base) { cout << "move" << endl;}
Base& operator=(Base&& base) { cout << "move=" << endl;}
};
Base b;
Base&& GetResult() {
return std::move(b);
}
int main() {
Base&& tmp = GetResult();
cout << &b << endl;
cout << &tmp << endl;
}
Production:
Base
0x6013a0
0x6013a0
~Base
Pourquoi move copy
et move operator=
ne sont-ils pas appelés? Et pourquoi l'adresse est la même?
3 réponses
Pour ajouter aux excellentes réponses existantes, je crois que le principal point de confusion est ce que fait std::move
.
std::move
ne bouge pas.
Son nom était épouvantable .
Il ne vous donne qu'une valeur x faisant référence à tout ce que vous lui avez donné; cette xvalue se liera à une référence rvalue là où une lvalue ne le sera pas. Cela signifie que le résultat de std::move
peut être donné à un constructeur de déplacement ou à un opérateur d'affectation de déplacement. Cependant, il ne fait pas cela pour vous, et vous ne le faites pas ici.
Compte tenu des critiques aussi vives pour la dénomination, vous avez sûrement une suggestion alternative
- user2079303
C'est un sujet très fréquenté, mais le créateur de C ++ suggère std::rval
, et l'un des architectes du C ++ moderne suggère std::rvalue_cast
(même si vous obtenez une valeur x ).
Personnellement, je pense que std::moveable
aurait été un bon compromis.
Pourquoi déplacer la copie et déplacer l'opérateur = ne pas être appelé?
Je suppose que par "déplacer la copie", vous voulez dire "déplacer le constructeur". L'opérateur d'affectation de déplacement n'est pas appelé, car vous n'utilisez jamais l'opérateur d'affectation.
Il n'y a pas de déplacements (ni de copies) car Base&&
est une référence (une référence r-value pour être précis). Les références font référence / pointent vers un objet - elles ne contiennent pas l'état de l'objet. Lorsque vous initialisez une référence, aucun objet n'est copié ou déplacé.
Et pourquoi l'adresse est la même?
Lorsque l'opérateur address-of est appliqué à une référence, vous obtenez l'adresse de l'objet référencé.
Ignorons la sémantique de déplacement pendant une minute et ne pensons qu'aux constructeurs de copie C ++ 98 familiers. Compte tenu du code suivant, quelle sortie attendez-vous?
class Base {
public:
Base() { cout << "Base" << endl;}
~Base() { cout << "~Base" << endl;}
Base(const Base& base) { cout << "Copy" << endl; }
Base& operator=(const Base& base) {cout << "operator=" << endl;}
};
Base b;
Base& GetResult() {
return b;
}
int main() {
Base& tmp = GetResult();
cout << &b << endl;
cout << &tmp << endl;
}
Bien sûr, vous vous attendez à un appel au constructeur par défaut Base
, suivi de l'adresse de b
imprimée deux fois, suivi du destructeur Base
. La raison en est que vous ne construisez qu'une seule instance Base
et que vous ne la copiez jamais - vous n'utilisez que des références.
C'est donc avec votre exemple. Vous utilisez des références rvalue plutôt que des références lvalue, mais le point est le même - il n'y a qu'une seule variable Base
, et aucune copie ou déplacement ne se produit . Si vous voulez voir la sémantique de déplacement en action, vous pouvez essayer quelque chose comme ceci:
Base getBase() {
return Base{};
}
int main() {
Base tmp = getBase();
Base other = std::move(tmp);
}
(Le déplacement de getBase()
sera probablement optimisé par le compilateur, mais vous devriez toujours voir le second.)
De nouvelles questions
c++
C ++ est un langage de programmation à usage général. Il a été conçu à l'origine comme une extension de C et a une syntaxe similaire, mais c'est maintenant un langage complètement différent. Utilisez cette balise pour les questions sur le code (à être) compilé avec un compilateur C ++. Utilisez une balise spécifique à la version pour les questions liées à une révision standard spécifique [C ++ 11], [C ++ 14], [C ++ 17], [C ++ 20] ou [C ++ 23], etc. .