Quelle est la différence entre std::move et std::forward

j'ai vu ça ici: Constructeur de Déplacement d'appel de la classe de base Constructeur de Déplacement

pourrait quelqu'un expliquer:

  1. la différence entre std::move et std::forward , de préférence avec quelques exemples de code?
  2. Comment penser facilement, et quand utiliser les
134
demandé sur Patryk 2012-03-12 21:20:52

3 réponses

std::move prend un objet et vous permet de le traiter comme une valeur temporaire. Bien que ce ne soit pas une exigence sémantique, typiquement une fonction acceptant une référence à une valeur de R l'invalidera. Quand vous voyez std::move , cela indique que la valeur de l'objet ne doit pas être utilisée après, mais vous pouvez toujours assigner une nouvelle valeur et continuer à l'utiliser.

std::forward a un cas d'utilisation unique: pour lancer un paramètre de fonction templated (à l'intérieur du fonction) à la catégorie de valeur (lvalue ou rvalue) que l'appelant utilisait pour la passer. Cela permet rvalue les arguments passés sur que rvalues, et lvalues être transmis que lvalues, un système appelé "transfert parfait."

à illustrent :

void overloaded( int const &arg ) { std::cout << "by lvalue\n"; }
void overloaded( int && arg ) { std::cout << "by rvalue\n"; }

template< typename t >
/* "t &&" with "t" being template param is special, and  adjusts "t" to be
   (for example) "int &" or non-ref "int" so std::forward knows what to do. */
void forwarding( t && arg ) {
    std::cout << "via std::forward: ";
    overloaded( std::forward< t >( arg ) );
    std::cout << "via std::move: ";
    overloaded( std::move( arg ) ); // conceptually this would invalidate arg
    std::cout << "by simple passing: ";
    overloaded( arg );
}

int main() {
    std::cout << "initial caller passes rvalue:\n";
    forwarding( 5 );
    std::cout << "initial caller passes lvalue:\n";
    int x = 5;
    forwarding( x );
}

comme le mentionne Howard, il y a aussi des similitudes car ces deux fonctions sont simplement moulées en type de référence. Mais en dehors de ces cas d'utilisation spécifiques (qui couvrent 99,9% des utilité des moulages de référence rvalue), vous devriez utiliser static_cast directement et écrire une bonne explication de ce que vous faites.

130
répondu Potatoswatter 2013-08-19 00:47:20

les deux std::forward et std::move ne sont que des moulages.

X x;
std::move(x);

l'expression de la valeur l x de type X est remplacée par une expression de la valeur R de type X (une valeur X pour être exacte). move peut également accepter une valeur R:

std::move(make_X());

et dans ce cas c'est une fonction d'identité: prend une valeur de type X et renvoie une valeur de type X.

avec std::forward vous pouvez sélectionner le destination dans une certaine mesure:

X x;
std::forward<Y>(x);

renvoie l'expression de valeur x de type X à une expression de type Y. Il y a des contraintes sur ce que peut être Y.

Y peut être accessible de Base de X, ou une référence à une Base de X. Y X, ou une référence à X. On ne peut pas jeté cv-qualifications avec forward , mais on peut ajouter cv-qualificatifs. Y ne peut pas être un type qui est simplement convertible à partir de X, sauf via une Base accessible conversion.

si Y est une référence de lvalue, le résultat sera une expression de lvalue. Si Y n'est pas une référence de lvalue, le résultat sera une expression de rvalue (xvalue pour être précis).

forward ne peut prendre un argument rvalue que si Y n'est pas une référence lvalue. C'est-à-dire que vous ne pouvez pas attribuer une valeur à lvalue. Pour des raisons de sécurité, cela conduit souvent à des références pendantes. Mais le casting d'une rvalue à rvalue est ok et autorisé.

Si vous essayez de spécifier Y à quelque chose qui n'est pas autorisé, l'erreur sera pris au moment de la compilation, pas de temps d'exécution.

55
répondu Howard Hinnant 2012-03-12 19:40:04

std::forward est utilisé pour forward paramètre exactement comme il a été passé à une fonction. Comme montré ici:

Lors de l'utilisation de std::avant d'avancer des arguments?

L'utilisation de std::move offre un objet comme une valeur R, pour éventuellement correspondre à un constructeur de mouvements ou à une fonction acceptant des valeurs R. Il le fait pour std::move(x) même si x n'est pas une valeur en soi.

19
répondu Bo Persson 2017-05-23 12:18:33