La fonction C ++ 11 std::move(x)
ne déplace vraiment rien du tout. C'est juste un casting à la valeur r. Pourquoi cela a-t-il été fait? N'est-ce pas trompeur?
c++
c++11
move-semantics
rvalue-reference
c++-faq
Howard Hinnant
la source
la source
std::move
bougent en fait ..std::char_traits::move
std::remove()
qui ne supprime pas les éléments: vous devez toujours appelererase()
pour supprimer réellement ces éléments du conteneur. Doncmove
ne bouge pas,remove
ne supprime pas. J'aurais choisi le nommark_movable()
pourmove
.mark_movable()
aussi déroutant. Cela suggère qu'il y a un effet secondaire durable là où il n'y en a pas.Réponses:
Il est correct que ce
std::move(x)
soit juste une conversion en rvalue - plus spécifiquement en une xvalue , par opposition à une prvalue . Et il est également vrai qu'avoir un casting nommémove
déroute parfois les gens. Cependant, l'intention de cette dénomination n'est pas de confondre, mais plutôt de rendre votre code plus lisible.L'histoire de
move
remonte à la proposition de déménagement d'origine en 2002 . Cet article présente d'abord la référence rvalue, puis montre comment écrire une méthode plus efficacestd::swap
:Il faut se rappeler qu'à ce stade de l'histoire, la seule chose que «
&&
» pouvait signifier était logique et . Personne n'était familier avec les références rvalue, ni avec les implications de transtyper une lvalue en rvalue (sans faire une copie comme lestatic_cast<T>(t)
ferait). Les lecteurs de ce code penseraient donc naturellement:Notez également qu'il ne
swap
s'agit en réalité que d'un substitut pour toutes sortes d'algorithmes de modification de permutation. Cette discussion est beaucoup , beaucoup plus grande queswap
.Ensuite, la proposition introduit le sucre de syntaxe qui remplace le
static_cast<T&&>
par quelque chose de plus lisible qui ne transmet pas le quoi précis , mais plutôt le pourquoi :Ie
move
est juste du sucre de syntaxe pourstatic_cast<T&&>
, et maintenant le code est assez évocateur quant à la raison pour laquelle ces transtypages sont là: pour activer la sémantique de déplacement!Il faut comprendre que dans le contexte de l'histoire, peu de gens à ce stade ont vraiment compris le lien intime entre les valeurs et la sémantique du mouvement (bien que l'article essaie également d'expliquer cela):
Si à l'époque
swap
était plutôt présenté comme ceci:Ensuite, les gens auraient regardé cela et auraient dit:
Le point principal:
En fait, en utilisant
move
, personne n'a jamais demandé:Au fil des années et de l'affinement de la proposition, les notions de lvaleur et de rvalue ont été affinées dans les catégories de valeur que nous avons aujourd'hui:
( l' image sans honte volée à dirkgently )
Et donc aujourd'hui, si nous voulions
swap
dire précisément ce qu'il fait, au lieu de pourquoi , cela devrait ressembler davantage à:Et la question que tout le monde devrait se poser est de savoir si le code ci-dessus est plus ou moins lisible que:
Ou même l'original:
Dans tous les cas, le programmeur C ++ compagnon doit savoir que sous le capot de
move
, il ne se passe rien de plus qu'un casting. Et le programmeur C ++ débutant, au moins avecmove
, sera informé que l'intention est de passer des rhs, par opposition à copier des rhs, même s'ils ne comprennent pas exactement comment cela est accompli.De plus, si un programmeur désire cette fonctionnalité sous un autre nom,
std::move
ne possède aucun monopole sur cette fonctionnalité, et aucune magie de langage non portable n'est impliquée dans son implémentation. Par exemple, si l'on voulait coderset_value_category_to_xvalue
, et l'utiliser à la place, c'est trivial de le faire:En C ++ 14, cela devient encore plus concis:
Donc, si vous êtes si enclin, décorez votre
static_cast<T&&>
comme bon vous semble, et vous finirez peut-être par développer une nouvelle meilleure pratique (C ++ est en constante évolution).Alors, que fait
move
-on en termes de code objet généré?Considérez ceci
test
:Compilé avec
clang++ -std=c++14 test.cpp -O3 -S
, cela produit ce code objet:Maintenant, si le test est changé en:
Il n'y a absolument aucun changement dans le code objet. On peut généraliser ce résultat à: Pour les objets trivialement mobiles ,
std::move
n'a aucun impact.Regardons maintenant cet exemple:
Cela génère:
Si vous exécutez à
__ZN1XaSERKS_
traversc++filt
elle produit:X::operator=(X const&)
. Pas de surprise ici. Maintenant, si le test est changé en:Ensuite, il n'y a toujours aucun changement dans le code objet généré.
std::move
n'a rien fait d'autrej
qu'un transtypage en rvalue, puis cette rvalueX
se lie à l'opérateur d'affectation de copie deX
.Ajoutons maintenant un opérateur d'affectation de déplacement à
X
:Maintenant , le code objet ne change:
Courir à
__ZN1XaSEOS_
traversc++filt
révèle queX::operator=(X&&)
est appelé au lieu deX::operator=(X const&)
.Et c'est tout ce qu'il y a à faire
std::move
! Il disparaît complètement au moment de l'exécution. Son seul impact est au moment de la compilation où il peut modifier l'appel de la surcharge.la source
digraph D { glvalue -> { lvalue; xvalue } rvalue -> { xvalue; prvalue } expression -> { glvalue; rvalue } }
pour le bien public :) Téléchargez ici SVGallow_move
;)movable
.std::move
àrvalue_cast
: youtube.com/...rvalue_cast
son sens est ambigu: quel type de rvalue renvoie-t-il?xvalue_cast
serait un nom cohérent ici. Malheureusement, la plupart des gens, à l'heure actuelle, ne comprendraient pas non plus ce qu'il fait. J'espère que dans quelques années, ma déclaration deviendra fausse.Permettez-moi de laisser ici une citation de la FAQ C ++ 11 écrite par B.Stroustrup, qui est une réponse directe à la question d'OP:
Au fait, j'ai vraiment apprécié la FAQ - cela vaut la peine d'être lu.
la source