web-dev-qa-db-fra.com

Pourquoi utilisez-vous std :: move lorsque vous avez && en C ++ 11?

Duplicata possible:
Quelqu'un peut-il m'expliquer s'il vous plaît déplacer la sémantique?

J'ai récemment assisté à un séminaire C++ 11 et les conseils suivants ont été donnés.

when you have && and you are unsure, you will almost always use std::move

Quelqu'un pourrait-il m'expliquer pourquoi vous devriez utiliser std::move par opposition à certaines alternatives et à certains cas où vous ne devriez pas utiliser std::move?

58
pyCthon

Premièrement, il y a probablement une idée fausse dans la question que je vais aborder:
Chaque fois que vous voyez T&& t Dans le code (et T est un type réel, pas un type de modèle), gardez à l'esprit que la catégorie de valeur de t est une valeur l (référence), plus une valeur r (temporaire). C'est très déroutant. Le T&& Signifie simplement que t est construit à partir d'un objet qui était une valeur r 1, mais t lui-même est une valeur l, pas une valeur r. S'il a un nom (dans ce cas, t) alors c'est une lvalue et ne se déplacera pas automatiquement, mais s'il n'a pas de nom (le résultat de 3+4) Alors c'est une rvalue et se déplacera automatiquement dans son résultat s'il le peut. Le type (dans ce cas T&&) N'a presque rien à voir avec la catégorie de valeur de la variable (dans ce cas, une valeur l ).

Cela étant dit, si vous avez T&& t Écrit dans votre code, cela signifie que vous avez une référence à une variable qui était temporaire, et vous pouvez détruire si vous le souhaitez. Si vous devez accéder à la variable plusieurs fois, vous ne voulez pas en std::move, Sinon elle perdrait sa valeur. Mais la dernière fois que vous accédez à t, il est sûr de std::move Sa valeur pour un autre T si vous le souhaitez. (Et 95% du temps, c'est ce que vous voulez faire). Tout cela s'applique également aux variables auto&&.

1. si T est un type de modèle, T&& Est une référence de transfert à la place, auquel cas vous utilisez std::forward<T>(t) au lieu de std::move(t) la dernière fois . Voir cette question .

85
Mooing Duck

J'ai trouvé cet article assez instructif sur le sujet des références de valeur en général. Il mentionne std::move vers la fin. C'est probablement la citation la plus pertinente:

Nous devons utiliser std::move, de <utility> - std::move est une façon de dire: "ok, honnête envers Dieu, je sais que j'ai une valeur, mais je veux que ce soit une valeur." std::move ne déplace rien en soi; il transforme simplement une lvalue en une rvalue, de sorte que vous pouvez invoquer le constructeur de déplacement.


Supposons que vous ayez un constructeur de déplacement qui ressemble à ceci:

MyClass::MyClass(MyClass&& other): myMember(other.myMember)
{
    // Whatever else.
}

Lorsque vous utilisez l'instruction other.myMember, la valeur renvoyée est une valeur l. Ainsi, le code utilise le constructeur copy pour initialiser this->myMember. Mais comme il s'agit d'un constructeur de déplacement, nous savons que other est un objet temporaire, et donc ses membres aussi. Nous voulons donc vraiment utiliser le constructeur - déplacer plus efficace pour initialiser this->myMember. En utilisant std::move s'assure que le compilateur traite other.myMember comme une référence rvalue et appelle le constructeur de déplacement, comme vous le souhaitez:

MyClass::MyClass(MyClass&& other): myMember(std::move(other.myMember))
{
    // Whatever else.
}

N'utilisez simplement pas std::move sur les objets dont vous avez besoin de rester - les constructeurs de mouvements sont à peu près garantis pour nettoyer tous les objets qui y sont passés. C'est pourquoi ils ne sont utilisés qu'avec des temporaires.

J'espère que ça t'as aidé!

26
Xavier Holt

Lorsque vous avez un objet de type T&&, une valeur r, cela signifie que cet objet peut être déplacé en toute sécurité, car personne d'autre ne dépendra plus tard de son état interne.

Comme le déplacement ne devrait jamais être plus cher que la copie, vous voudrez presque toujours le déplacer. Et pour le déplacer, vous devez utiliser le std::move une fonction.

Quand faut-il éviter std::move, même si ce serait sûr? Je ne l'utiliserais pas dans des exemples triviaux, par exemple:

 int x = 0;
 int y = std::move(x);

À côté de cela, je ne vois aucun inconvénient. Si cela ne complique pas le code, le déplacement doit être effectué autant que possible à mon humble avis.

Un autre exemple, où vous ne voulez pas vous déplacer, ce sont les valeurs de retour. Le langage garantit que les valeurs de retour sont (au moins) déplacées, vous ne devez donc pas écrire

return std::move(x); // not recommended

(Si vous êtes chanceux, optimisation de la valeur de retour hits, ce qui est encore mieux qu'une opération de déplacement.)

3
Philipp Claßen

Vous pouvez utiliser move lorsque vous devez "transférer" le contenu d'un objet ailleurs, sans faire de copie. Il est également possible pour un objet de prendre le contenu d'un objet temporaire sans faire de copie, avec std :: move.

Vérifiez ce lien

1
Rahul Tripathi