1. "¿Qué es?"
Si bien std::move()
técnicamente es una función, diría que no es realmente una función . Es una especie de convertidor entre las formas en que el compilador considera el valor de una expresión.
2. "¿Qué hace?"
Lo primero a tener en cuenta es que std::move()
realidad no mueve nada . Convierte una expresión de ser un valor l (como una variable con nombre) a ser un valor x . Un xvalue le dice al compilador:
Puedes saquearme, mover todo lo que tengo y usarlo en otro lugar (ya que de todos modos voy a ser destruido pronto) ".
en otras palabras, cuando usas std::move(x)
, estás permitiendo que el compilador canibalice x
. Por lo tanto, si x
tiene, por ejemplo, su propio búfer en la memoria, después destd::move()
de que el compilador puede tener otro objeto propio.
También puedes moverte desde un valor priva (como un temporal que estás pasando), pero esto rara vez es útil.
3. "¿Cuándo se debe usar?"
Otra forma de hacer esta pregunta es "¿Para qué canibalizaría los recursos de un objeto existente?" bueno, si estás escribiendo código de aplicación, probablemente no estarás jugando mucho con objetos temporales creados por el compilador. Por lo tanto, principalmente haría esto en lugares como constructores, métodos de operador, funciones similares a algoritmos de biblioteca estándar, etc., donde los objetos se crean y destruyen mucho de forma automática. Por supuesto, eso es solo una regla general.
Un uso típico es 'mover' recursos de un objeto a otro en lugar de copiarlos. @Guillaume enlaza a esta página que tiene un ejemplo breve y sencillo: intercambiar dos objetos con menos copia.
template <class T>
swap(T& a, T& b) {
T tmp(a); // we now have two copies of a
a = b; // we now have two copies of b (+ discarded a copy of a)
b = tmp; // we now have two copies of tmp (+ discarded a copy of b)
}
El uso de mover le permite intercambiar los recursos en lugar de copiarlos:
template <class T>
swap(T& a, T& b) {
T tmp(std::move(a));
a = std::move(b);
b = std::move(tmp);
}
Piense en lo que sucede cuando T
es, por ejemplo, vector<int>
de tamaño n. En la primera versión, lee y escribe 3 * n elementos, en la segunda versión básicamente lee y escribe solo los 3 punteros en los buffers de los vectores, más los tamaños de los 3 buffers. Por supuesto, la clase T
necesita saber cómo moverse; su clase debe tener un operador de asignación de movimiento y un constructor de movimiento para la clase T
para que esto funcione.