2012-07-20 24 views
17

Supongamos que tengo el siguiente código:Mover con el vector :: push_back

#include <vector> 
struct A { 
    int a; 
    int x; 
}; 
int main() { 
    using namespace std; 
    A a1; 
    A a2; 
    vector<A> va; 
    va.push_back(a1); 
    va.push_back(move(a2)); 
} 

Soy consciente de que los elementos de std :: vector se almacenan de forma contigua, a diferencia de un std :: lista. En el código anterior a2 se mueve pero ¿realmente no hay copia de a2 en el vector va? ¿Cuál es la diferencia entre va.push_back(a2); y ?

+2

En su caso, 'std :: move'ing' a2' hace exactamente * nada *, ya que es un tipo plano (es decir, no tiene datos externos) y solo copiará. – Xeo

+0

@cdhowie Gracias. corregido – ggg

+0

Es posible que desee leer [¿Puede explicarme alguien la semántica de movimiento?] (Http://stackoverflow.com/questions/3106110/) para obtener una introducción a la semántica de movimientos. – fredoverflow

Respuesta

26

En su caso, no hay una diferencia efectiva, ya que está utilizando constructores de copia provistos por el compilador. Verá una notable diferencia en el rendimiento cuando use objetos que sean fáciles de mover y le costará mucho copiar. En ese caso, usar push_back(x) crearía una copia del objeto, mientras que push_back(move(x)) diría push_back() que puede "robar" el contenido de x, dejando x en un estado inutilizable e indefinido.

Considere si tenía un vector de listas (std::vector<std::list<int> >) y desea insertar una lista que contenga 100.000 elementos. Sin move(), se copiará toda la estructura de la lista y todos los 100.000 elementos. Con move(), algunos punteros y otros pequeños bits de datos se barajan, y eso es todo. Esto será mucho más rápido y requerirá menos consumo de memoria en general.

+1

¿Por qué? mover c-tor se generará automáticamente, ¿no? – ForEveR

+6

@ForEveR No importa si se genera automáticamente o no, porque no hay asignaciones en la estructura 'A' que se pueden mover. Solo tiene dos 'int's, y el constructor de movimientos hará lo mismo que el constructor de copias: asigne los valores almacenados en las entradas del objeto fuente al nuevo objeto. No hay posibilidad de optimización en el escenario de movimiento con este tipo, porque ya es lo más óptimo que puede obtener. – cdhowie

+0

@cdhowie Entonces, ¿siempre se copiará algo durante un movimiento? – ggg

14

Cuando se utiliza la versión va.push_back(a2)vector<T>::push_back(const T&) serán llamados, cuando se utiliza la versión va.push_back(move(a2))vector<T>::push_back(T&&) se llamará ...

Pero en su caso no hay diferencia de Desempeño, ya

15 El constructor copia/movimiento implícitamente definido para una clase no sindicalizada X realiza una copia/movimiento de sus bases y miembros para miembros.

Párrafo 12.8 n3337 borrador.

0

Quiero señalar algo que otras respuestas no han pasado; es que el ?.push_back(move(?)) será más lento que ?.push_back(?) en su caso (cuando tiene objetos que se pueden copiar trivialmente), porque el constructor de movimientos debe poner a cero \ establecer el objeto movido, lo que efectivamente está escribiendo \ copiando dos objetos.

+0

Un constructor de movimiento no está obligado a hacer nada con el objeto movido. No es necesario poner a cero nada a menos que haya punteros movidos que deben restablecerse a cero. (Los constructores de movimiento generados por el compilador no van a cubrir, poner a cero el objeto fuente). – cdhowie

Cuestiones relacionadas