¿Por qué usas std :: move cuando tienes && en C ++ 11?

Posible duplicado:
¿Alguien puede explicarme la semántica del movimiento?

Recientemente asistí a un seminario de C ++ 11 y recibí el siguiente consejo.

when you have && and you are unsure, you will almost always use std::move 

¿Podría alguien explicarme por qué debería usar std::move en lugar de algunas alternativas y algunos casos en los que no debe usar std::move ?

Primero, probablemente haya una idea errónea en la pregunta que abordaré:
Siempre que vea T&& t en el código (y T es un tipo real, no un tipo de plantilla), tenga en cuenta que la categoría de valor de t es un valor t (referencia), no un valor r (temporal) más. Es muy confuso El T&& meramente significa que t se construye a partir de un objeto que era un valor r 1 , pero t mismo es un valor l, no un valor r. Si tiene un nombre (en este caso, t ), entonces es un valor l y no se moverá automáticamente, pero si no tiene nombre (el resultado de 3+4 ), entonces es un valor r y se moverá automáticamente a su resultado si puede. El tipo (en este caso T&& ) casi no tiene nada que ver con la categoría de valor de la variable (en este caso, un valor l).

Dicho esto, si tiene T&& t escrito en su código, eso significa que tiene una referencia a una variable que era temporal, y está bien destruirla si así lo desea. Si necesita acceder a la variable varias veces, no desea que std::move de ella, de lo contrario perderá su valor. Pero la última vez que acceda es seguro std::move su valor a otra T si lo desea. (Y el 95% de las veces, eso es lo que quieres hacer). Todo esto también se aplica a auto&& variables auto&& .

1. si T es un tipo de plantilla, T&& es una referencia de reenvío, en cuyo caso utiliza std::forward(t) lugar de std::move(t) la última vez. Ver esta pregunta

Encontré este artículo bastante esclarecedor sobre el tema de las referencias de valores en general. Él menciona std::move hacia el final. Esta es probablemente la cita más relevante:

Necesitamos usar std::move , de std::move es una forma de decir, “ok, honesto para Dios, sé que tengo un lvalue, pero quiero que sea un valor”. std::move no std::move nada en sí mismo; simplemente convierte un valor l en un valor r, para que pueda invocar el constructor de movimiento.


Digamos que tienes un constructor de movimientos que se ve así:

 MyClass::MyClass(MyClass&& other): myMember(other.myMember) { // Whatever else. } 

Cuando utiliza la instrucción other.myMember , el valor que se devuelve es un lvalue. Por lo tanto, el código utiliza el constructor de copia para inicializar this->myMember . Pero como se trata de un constructor de movimientos, sabemos que other es un objeto temporal y, por lo tanto, también lo son sus miembros. Entonces realmente queremos usar el constructor de movimientos más eficiente para inicializar this->myMember . El uso de std::move garantiza que el comstackdor trate other.myMember como una referencia rvalue y llame al constructor de movimientos, como lo desearía:

 MyClass::MyClass(MyClass&& other): myMember(std::move(other.myMember)) { // Whatever else. } 

Simplemente no use std::move en los objetos que necesita mantener a su alrededor: los constructores de movimiento tienen la garantía de desmantelar cualquier objeto que se les pase. Es por eso que solo se usan con temporarios.

¡Espero que ayude!

Cuando tienes un objeto de tipo T&& , a rvalue, significa que este objeto es seguro para ser movido, ya que nadie más dependerá más tarde de su estado interno.

Como mover nunca debería ser más caro que copiar, casi siempre querrá moverlo. Y para moverlo, debe usar la función std::move .

¿Cuándo debería evitar std::move , incluso si fuera seguro? No lo usaría en ejemplos triviales, por ejemplo ,:

  int x = 0; int y = std::move(x); 

Además de eso, no veo inconvenientes. Si no complica el código, se debe mover siempre que sea posible en mi humilde opinión.

Otro ejemplo, donde no quieres moverte son los valores de retorno. El lenguaje garantiza que los valores de retorno se muevan (al menos), por lo que no debe escribir

 return std::move(x); // not recommended 

(Si tiene suerte, devuelva los resultados de optimización de valor , que es incluso mejor que una operación de movimiento).

Puedes usar mover cuando necesites “transferir” el contenido de un objeto a otro lugar, sin hacer una copia. También es posible que un objeto tome el contenido de un objeto temporal sin hacer una copia, con std :: move.

Ver este enlace