96 votes

Comment std :: move () transfère-t-il des valeurs dans RValues?

Je viens de trouver moi-même pas de comprendre pleinement la logique de l' std::move().

Au premier abord, je l'ai googlé mais semble comme il y a seulement des documents sur la façon d'utiliser std::move(), pas comment sa fonctionne la structure.

Je veux dire, je sais ce que le modèle de la fonction membre est mais quand je regarde en std::move() définition dans VS2010, il est encore confuse.

la définition de std::move() va ci-dessous.

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);
    }

Ce qui est bizarre première pour moi, c'est le paramètre, (_Ty&& _Arg), parce que quand j'ai appeler la fonction comme vous le voyez ci-dessous,

// main()
Object obj1;
Object obj2 = std::move(obj1);

essentiellement, il est égal à

// std::move()
_Ty&& _Arg = Obj1;

Mais comme vous le savez déjà, vous ne pouvez pas relier directement une LValue à une référence RValue, qui me fait penser qu'il devrait en être ainsi.

_Ty&& _Arg = (Object&&)obj1;

Cependant, ce qui est absurde, parce que std::move() pour toutes les valeurs.

Donc je suppose que pour bien comprendre comment cela fonctionne, je devrais prendre un coup d'oeil à ces structures trop.

template<class _Ty>
struct _Remove_reference
{   // remove reference
    typedef _Ty _Type;
};

template<class _Ty>
struct _Remove_reference<_Ty&>
{   // remove reference
    typedef _Ty _Type;
};

template<class _Ty>
struct _Remove_reference<_Ty&&>
{   // remove rvalue reference
    typedef _Ty _Type;
};

Malheureusement, c'est toujours aussi confus et je ne l'obtenez pas.

Je sais que c'est à cause de mon manque de syntaxe de base des compétences sur le C++. Je voudrais savoir comment celles-ci fonctionnent à fond et tous les documents que je peux obtenir sur l'internet sera plus que bienvenue. (Si vous ne pouvez expliquer ça, ça va être génial aussi).

161voto

Vitus Points 6861

Nous commençons avec la fonction de déplacement (dont j'ai nettoyé un peu):

template <typename T>
typename remove_reference<T>::type&& move(T&& arg)
{
  return static_cast<typename remove_reference<T>::type&&>(arg);
}

Commençons par le plus facile - c'est, lorsque la fonction est appelée avec rvalue:

Object a = std::move(Object());
// Object() is temporary, which is prvalue

et notre move modèle est instancié comme suit:

// move with [T = Object]:
remove_reference<Object>::type&& move(Object&& arg)
{
  return static_cast<remove_reference<Object>::type&&>(arg);
}

Depuis remove_reference convertit T& de T ou T&& de T, et Object n'est pas de référence, notre dernière fonction est:

Object&& move(Object&& arg)
{
  return static_cast<Object&&>(arg);
}

Maintenant, vous pourriez vous demander: avons-nous encore besoin de la fonte? La réponse est: oui, nous le faisons. La raison en est simple; nommé référence rvalue est traitée comme lvalue (et la conversion implicite de lvalue de référence rvalue est interdit par la norme).


Voici ce qui arrive lorsque nous appelons move avec lvalue:

Object a; // a is lvalue
Object b = std::move(a);

et correspondante move instanciation:

// move with [T = Object&]
remove_reference<Object&>::type&& move(Object& && arg)
{
  return static_cast<remove_reference<Object&>::type&&>(arg);
}

Encore une fois, remove_reference convertit Object& de Object et nous obtenons:

Object&& move(Object& && arg)
{
  return static_cast<Object&&>(arg);
}

Nous en arrivons maintenant à la partie la plus délicate: qu'est - Object& && même signifie, et comment peut-il se lier à lvalue?

Pour permettre le transfert parfait, C++11 est la norme prévoit des règles spéciales de référence de l'effondrement, qui sont comme suit:

Object &  &  = Object &
Object &  && = Object &
Object && &  = Object &
Object && && = Object &&

Comme vous pouvez le voir, en vertu de ces règles, Object& && signifie, en réalité, Object&, ce qui est de la plaine lvalue de référence qui permet de lier lvalues.

Final est donc:

Object&& move(Object& arg)
{
  return static_cast<Object&&>(arg);
}

ce qui n'est pas, contrairement à la précédente instanciation avec rvalue - ils à la fois jeté son argument de référence rvalue, puis le retourner. La différence est que la première instanciation peut être utilisé avec des rvalues seulement, tandis que le second travaille avec des lvalues.


Pour expliquer pourquoi nous avons besoin d' remove_reference un peu plus, nous allons essayer cette fonction

template <typename T>
T&& wanna_be_move(T&& arg)
{
  return static_cast<T&&>(arg);
}

et l'instancier avec lvalue.

// wanna_be_move [with T = Object&]
Object& && wanna_be_move(Object& && arg)
{
  return static_cast<Object& &&>(arg);
}

L'application de la référence de l'effondrement des règles mentionnées ci-dessus, vous pouvez voir que nous obtenons la fonction qui est inutilisable en l' move (pour le dire simplement, vous l'appelez avec lvalue, vous obtenez lvalue arrière). Si quoi que ce soit, cette fonction est la fonction identité.

Object& wanna_be_move(Object& arg)
{
  return static_cast<Object&>(arg);
}

4voto

Vaughn Cato Points 30511

_Ty est un paramètre du modèle, et dans cette situation

Object obj1;
Object obj2 = std::move(obj1);

_Ty est le type d'Objet"&"

c'est pourquoi la _Remove_reference est nécessaire.

Il serait plus comme

typedef Object& ObjectRef;
Object obj1;
ObjectRef&& obj1_ref = obj1;
Object&& obj2 = (Object&&)obj1_ref;

Si nous n'avons pas de supprimer la référence qu'il serait comme nous faisions

Object&& obj2 = (ObjectRef&&)obj1_ref;

Mais ObjectRef&& réduit à un Objet &, qui n'était pas le lier à obj2.

La raison pour laquelle il réduit de cette façon est de soutenir le transfert parfait. Voir ce document.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X