7
votes

Quelle est la magie de std: bouge

Les codes suivants font échouer VC2010:

template<class _Ty> inline
    typename tr1::_Remove_reference<_Ty>::_Type&&
        move(_Ty&& _Arg)
    {   // forward _Arg as movable
    return ((typename tr1::_Remove_reference<_Ty>::_Type&&)_Arg);
    }


2 commentaires

Dans le second cas, x est une référence rvalue , ce n'est pas une rvalue elle-même (car elle a un nom).


Stackoverflow.com/questions/5529881/... < / a> Stackoverflow.com/ Questions / 7510182 / ...


5 Réponses :


4
votes

Vous pouvez penser à std :: Déplacer comme juste une distribution (mais une expression couler, pas un type de type de type). L'expression std :: mouvement (x) est une rvalue avec la même valeur que x , mais cela fonctionne même si x est un lvalue .

dans votre exemple "code2", x est en effet une lvalue (de type "RValue référence à la chaîne"). Ce lvalue ne peut pas se lier au type de retour de la fonction ("Revalue référence à la chaîne"), de sorte que vous devez la jeter explicitement à une expression de rvalue.

Nous pouvons également faire le contraire de déplacer , que j'appelle habituellement restez , qui transforme les rvalues ​​en lvalues ​​(utilisation avec soin!): xxx

Ceci est principalement utile pour one-liners pervers ou impressionner les filles à un bar.


0 commentaires

10
votes

std :: Déplacer S est une référence de rvalue, qui semble confusion - pourquoi pouvez-vous appeler déplacer (STR) , lorsque STR n'est pas une rvalue?

L'astuce Voici que les références de rvalue fonctionnent de manière conforelle sur les paramètres de modèle:

Si le paramètre de modèle t est int < / code>, puis t && sera une référence de rvalue int && .
Mais si t est une référence de lvalue int & , puis t && sera également de référence de lvalue int & . .

Ceci est à cause du chemin & et && combine: xxx

donc lorsque vous appelez déplacer (STR) , t est std :: string & et le type de paramètre de déplacer est Aussi std :: string & - une référence de Lvalue, qui permet à l'appel de la fonction de compiler. Ensuite, tous les déplacer doivent faire la valeur à une référence de rvalue.


1 commentaires

+1 Ah, vous avez repéré la confusion de l'Op beaucoup mieux. Le type d'argument de n'est pas une référence de rvalue, mais une référence universelle .



0
votes

Il y a quelques articles pour expliquer n ° 1, mais je ne comprends pas pourquoi # 2 Également échoue. P>

N'oubliez pas que s'il a un nom, c'est un lvalue fort>. Dans votre deuxième cas, X est toujours un lvalue fort> même s'il s'agit d'une référence RValue forte>. Std :: Déplacer Code> a la capacité de transformer lvalues ​​ forte> dans RValues ​​ forte> en ne faisant rien de plus qu'un static_cast (Yourvar) sur eux. L'expression résultante est une r devale qui peut être acceptée par n'importe quel code demandant une référence RValue forte>. (un type && code>) p>

Je vais illustrer avec quelques exemples. Dans votre exemple d'origine, remplacez: p> xxx pré>

avec p> xxx pré>

là, l'objet String n'a plus de nom, il est maintenant une rvalue forte> et est acceptée par test1. P>

Comment fonctionne-t-elle? Encore une fois, assez simple. Encore une fois, remplacez votre appel par: p>

test1(static_cast<std::string&&>(str));


0 commentaires

3
votes

Les gens ici ont déjà répondu à la question, mais je pense que cela doit être dit plus explicitement. La raison pour laquelle les gens sont souvent confondus avec des références de rvalue sont dans la règle:

a nommé référence de rvalue est un lvalue .

déroutant au début, cette règle a du sens. L'objectif d'une référence de rvalue est de se lier à l'objet que vous n'aurez plus besoin de: soit à une temporaire ni à quelque chose que vous savez que vous n'aurez jamais besoin, mais le compilateur ne serait pas en mesure de le comprendre.

Une référence de rvalue nommée est quelque chose que vous pouvez faire référence à plusieurs fois: xxx

ici, j'ai créé une temporaire dans la première ligne mais À la reliure à la référence de la rvalue, je l'ai fait fonctionner presque comme un objet automatique: je peux y accéder plusieurs fois. Et pour que la dernière ligne fonctionne, la deuxième ligne ne doit pas compiler.

Que std :: Déplacer est de modifier une référence de rvalue nommée (une lvalue) vers un Référence de rvalue sans nom (une rvalue).


0 commentaires

0
votes

La magie de la sémantique de déplacement consiste à exploiter la destruction.

Imaginez une classe qui gère la durée de vie d'un tampon alloué de manière dynamique comme STD :: String: Un constructeur de copie prenant String Const & ne peut pas savoir si l'argument est réellement nécessaire après et doit donc toujours cloner ce tampon, ce qui peut être une opération coûteuse.

Si nous pouvons (en surchargeant le constructeur de copie pour String && ) Sachez que l'argument est jetable, nous ne pouvons que "voler" le tampon de ne pas avoir à copier (sur et sur des expressions complexes).

Comme indiqué précédemment, une référence de rvalue est une lvalue (cela nous a permis d'accéder complet afin de voler le tampon dans l'exemple ci-dessus). Supposons maintenant que nous voulions utiliser l'argument dans Un autre, expression d'appel surchargé de simulaire: sans std :: Déplacer L'argument nous semble précieux et que la surcharge String Const & est résolue alors que std :: Déplacer nous permet Pour répéter le "bouge de mouvement" (parce que nous savons que l'argument provenait d'une r devalue sur le site d'appel).


0 commentaires