J'ai vu ceci ici: Move Constructor appelant Move Constructor de classe de base
Quelqu'un pourrait-il expliquer:
- la différence entre
std::move
etstd::forward
, de préférence avec quelques exemples de code? - Comment y penser facilement et quand utiliser lequel
c++
c++11
perfect-forwarding
aCuria
la source
la source
move
lorsque vous souhaitez déplacer une valeur, etforward
lorsque vous souhaitez utiliser un transfert parfait. Ce n'est pas sorcier ici;)Réponses:
std::move
prend un objet et vous permet de le traiter comme temporaire (une rvalue). Bien que ce ne soit pas une exigence sémantique, généralement une fonction acceptant une référence à une rvalue l'invalidera. Lorsque vous voyezstd::move
, cela indique que la valeur de l'objet ne doit pas être utilisée par la suite, mais vous pouvez toujours attribuer une nouvelle valeur et continuer à l'utiliser.std::forward
a un seul cas d'utilisation: pour convertir un paramètre de fonction basé sur un modèle (à l'intérieur de la fonction) dans la catégorie de valeur (lvalue ou rvalue) que l'appelant a utilisée pour le transmettre. Cela permet aux arguments rvalue d'être passés en tant que rvalues et de lvalues à passer en tant que lvalues, un schéma appelé «transfert parfait».Pour illustrer :
Comme le mentionne Howard, il existe également des similitudes car ces deux fonctions sont simplement converties en type de référence. Mais en dehors de ces cas d'utilisation spécifiques (qui couvrent 99,9% de l'utilité des casts de référence rvalue), vous devez utiliser
static_cast
directement et écrire une bonne explication de ce que vous faites.la source
std::forward
le seul cas d'utilisation est la transmission parfaite des arguments de fonction. J'ai rencontré des situations dans lesquelles je veux transmettre parfaitement d'autres choses, comme des membres d'objet.Les deux
std::forward
etstd::move
ne sont que des moulages.Ce qui précède convertit l'expression lvalue
x
de type X en une expression rvalue de type X (une valeur x pour être exacte).move
peut également accepter une rvalue:et dans ce cas c'est une fonction d'identité: prend une rvalue de type X et retourne une rvalue de type X.
Avec
std::forward
vous pouvez sélectionner la destination dans une certaine mesure:Convertit l'expression lvalue
x
de type X en une expression de type Y. Il existe des contraintes sur ce que Y peut être.Y peut être une base accessible de X, ou une référence à une base de X. Y peut être X, ou une référence à X. On ne peut pas rejeter les qualificatifs cv avec
forward
, mais on peut ajouter des qualificatifs cv. Y ne peut pas être un type simplement convertible à partir de X, sauf via une conversion de base accessible.Si Y est une référence lvalue, le résultat sera une expression lvalue. Si Y n'est pas une référence lvalue, le résultat sera une expression rvalue (xvalue pour être précis).
forward
peut prendre un argument rvalue uniquement si Y n'est pas une référence lvalue. Autrement dit, vous ne pouvez pas convertir une rvalue en lvalue. Ceci est pour des raisons de sécurité car cela conduit généralement à des références pendantes. Mais le cast d'une rvalue en rvalue est correct et autorisé.Si vous essayez de spécifier Y pour quelque chose qui n'est pas autorisé, l'erreur sera interceptée au moment de la compilation, pas au moment de l'exécution.
la source
std::forward
, puis une fois cette fonction exécutée, puis-je utiliser cet objet? Je suis conscient que, dans le cas destd::move
, c'est un comportement indéfini.move
: stackoverflow.com/a/7028318/576911 Carforward
, si vous passez une lvalue, votre API doit réagir comme si elle recevait une lvalue. Normalement, cela signifie que la valeur ne sera pas modifiée. Mais s'il s'agit d'une valeur non constante, votre API l'a peut-être modifiée. Si vous transmettez une rvalue, cela signifie normalement que votre API peut en avoir été déplacée, et donc stackoverflow.com/a/7028318/576911 s'appliquerait.std::forward
est utilisé pour transmettre un paramètre exactement comme il a été passé à une fonction. Tout comme montré ici:Quand utiliser std :: forward pour transférer des arguments?
L'utilisation
std::move
offre un objet comme rvalue, pour éventuellement correspondre à un constructeur de déplacement ou à une fonction acceptant des rvalues. Il fait celastd::move(x)
même si cex
n'est pas une valeur en soi.la source