2012-07-20 9 views
17

Supponiamo che io ho il seguente codice:Sposta con 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)); 
} 

Sono consapevole del fatto che gli elementi di std :: vector sono memorizzati in modo contiguo, a differenza di uno std :: list. Nel codice sopra riportato a2 viene spostato, ma non c'è davvero nessuna copia di a2 nel vettore va? Qual è la differenza tra va.push_back(a2); e ?

+2

Nel tuo caso, 'std :: move'ing' a2' fa esattamente * niente *, poiché è un tipo piatto (vale a dire, non ha dati esterni) e continuerà a copiare. – Xeo

+0

@cdhowie Grazie. corretto. – ggg

+0

Si consiglia di leggere [Qualcuno può spiegare a me la semantica del movimento?] (Http://stackoverflow.com/questions/3106110/) per un'introduzione alla semantica del movimento. – fredoverflow

risposta

26

Nel tuo caso, non c'è alcuna differenza effettiva, dal momento che stai usando costruttori di copie forniti dal compilatore. Si noterà una notevole differenza di prestazioni quando si utilizzano oggetti che sono costruibili con il movimento e si deve fare molto per copiare. In tal caso, utilizzando push_back(x) creerebbe una copia dell'oggetto, mentre push_back(move(x)) direbbe push_back() che potrebbe "rubare" il contenuto di x, lasciando x in uno stato non utilizzabile e non definito.

Considerare se si disponesse di un vettore di elenchi (std::vector<std::list<int> >) e si desiderava premere un elenco contenente 100.000 elementi. Senza move(), l'intera struttura della lista e tutti i 100.000 elementi verranno copiati. Con move(), alcuni puntatori e altri piccoli bit di dati vengono spostati in giro, e questo è tutto. Questo sarà molto più veloce e richiederà un minor consumo di memoria complessivo.

+1

Perché? move c-tor verrà generato automaticamente, non è così? – ForEveR

+6

@ForEveR Non importa se uno viene generato automaticamente o meno, perché non ci sono allocazioni nella struttura 'A' che può essere spostata. Avete solo due 'int's, e il costruttore di move farà la stessa cosa che farà il costruttore di copie: assegnate i valori memorizzati negli oggetti nell'oggetto sorgente al nuovo oggetto. Non vi è alcuna possibilità di ottimizzazione nello scenario di spostamento con questo tipo, poiché è già ottimale come si può ottenere. – cdhowie

+0

@cdhowie Quindi qualcosa verrà sempre copiato durante una mossa? – ggg

14

Quando si utilizza la versione va.push_back(a2)vector<T>::push_back(const T&) saranno chiamati, quando si utilizza la versione va.push_back(move(a2))vector<T>::push_back(T&&) sarà chiamato ...

ma nel tuo caso non c'è alcuna differenza per la perfomance, dal momento che

15 Il Costruttore di copia/spostamento implicitamente definito per una classe non di unione X esegue una copia/spostamento membro delle sue basi e membri.

Paragrafo 12.8 n3337 abbozzo.

0

Voglio notare qualcosa che altre risposte non sono state superate; è che il ?.push_back(move(?)) sarà più lento di ?.push_back(?) nel tuo caso (quando hai oggetti banalmente copiabili), perché il costruttore di movimento deve azzerare \ impostare l'oggetto spostato, che in effetti stai scrivendo \ copiando due oggetti.

+0

Un costruttore di mosse non è obbligato a fare nulla sull'oggetto spostato. Non è necessario azzerare nulla a meno che non vi siano puntatori spostati che devono essere ripristinati su null. (I costruttori di movimento generati dal compilatore non hanno intenzione di azzerare l'oggetto di origine). – cdhowie

Problemi correlati