2013-02-27 19 views
7

Sto lavorando con un programma che utilizza molto lo std::vector. Inoltre ci sono un sacco di allocazioni/deallocazioni in atto, miliardi di loro, e sto cercando di evitarne il maggior numero possibile. Dato che sono relativamente nuovo al C++, ho alcune domande riguardanti le allocazioni che si verificano quando si utilizza un vettore (ad esempio quando si aggiungono elementi ad esso). Sono su una macchina Win7 a 64 bit, il programma è a 32 bit e sto usando la versione corrente dei compilatori MinGW.Quando viene copiato un vettore, quando viene passato un riferimento?

Mi piacerebbe sapere, ciò che accade nei seguenti casi, vale a dire se il vettore viene copiato, passato come un punto di riferimento, ...

1.

std::vector<T> fillVector() { 
    std::vector<T> returnVector; 
    ... 
    return returnVector; 
} 

std::vector<T> myVector = fillVector(); 

2.

std::vector<T>& fillVector() { 
    std::vector<T>* returnVector = new std::vector<T>; 
    ... 
    return (*returnVector); 
} 

std::vector<T> myVector = fillVector(); 

3.

std::vector<T>* fillVector() { 
    std::vector<T>* returnVector = new std::vector<T>; 
    ... 
    return returnVector; 
} 

std::vector<T>* myVector = fillVector(); 

e le seguenti, diverse operazioni:

4.

std::vector<T> myVector1; 
... (myVector1 being filled) 
std::vector<T> myVector = myVector1; 

5.

std::vector<T>* myVector1 = new std::vector<T>; 
... (myVector1 being filled) 
std::vector<T> myVector = (*myVector1); 

Supponendo che non voglio cambiare l'argomento in myFunction/modifiche per myVector in myFunction wouldn non fa male al resto del programma:

6.

void myFunction(std::vector<T> myParam) { 
    ... 
} 

std::vector<T> myVector; 
... (myVector being filled) 
myFunction(myVector); 

7.

void myFunction(std::vector<T>& myParam) { 
    ... 
} 

std::vector<T> myVector; 
... (myVector being filled) 
myFunction(myVector); 

Se la mia comprensione è corretta, le opzioni più veloci (cioè i riferimenti di passaggio invece di creare copie e passarli) sarebbe 2/3, 5 e 7. Si prega di correggetemi se Mi sbaglio!

+1

Il più veloce e più pulito è l'opzione 1. – juanchopanza

risposta

1

L'opzione 1 più veloce e più idiomatica. Entrambe le copie (da returnVector per restituire il valore e dal valore restituito a myVector) verranno quasi certamente eliminate dal compilatore. Copia elision è un'ottimizzazione che il compilatore può fare che comporta la rimozione di eventuali copie non necessarie. Qui, entrambe le copie non sono necessarie e lo std::vector verrà costruito direttamente al posto di myVector.

Infatti, anche se si disabilitano le ottimizzazioni di copia elision con il compilatore, in C++ 11 entrambe le copie saranno effettivamente mosse. Lo spostamento di std::vector richiede alcuni compiti ed è molto veloce. Il primo è considerato una mossa da una regola speciale e il secondo è una mossa perché l'espressione fillVector() è un'espressione di valore.

+0

Questo spiega alcuni degli esperimenti che ho fatto, che per me non avevano alcun senso. – MrWayne

7

1.

std::vector<T> fillVector() { 
    std::vector<T> returnVector; 
    ... 
    return returnVector; 
} 

std::vector<T> myVector = fillVector(); 

questo va bene. Lo vector viene restituito in base al valore, ma la chiamata al costruttore di copie viene eliminata dalla maggior parte dei compilatori (almeno quando le ottimizzazioni sono attivate) in Ottimizzazione del valore restituito (denominato).

Inoltre, con C++ 11, spostare la semantica assicura che venga richiamato il costruttore di movimento anziché il costruttore di copie, che semplicemente ruberà l'intestino del vettore restituito senza generare una copia costosa.

2.

std::vector<T>& fillVector() { 
    std::vector<T>* returnVector = new std::vector<T>; 
    ... 
    return (*returnVector); 
} 

std::vector<T> myVector = fillVector(); 

non fare questo. Sovraccarico non necessario dell'assegnazione dinamica, oltre all'onere di dover ricordare che è necessario deallocare l'oggetto restituito. Evitare di gestione manuale della memoria e preferiscono 1.

3.

std::vector<T>* fillVector() { 
    std::vector<T>* returnVector = new std::vector<T>; 
    ... 
    return returnVector; 
} 

std::vector<T>* myVector = fillVector(); 

Idem come sopra. Evitare la gestione manuale della memoria.

4.

std::vector<T> myVector1; 
... (myVector1 being filled) 
std::vector<T> myVector = myVector1; 

Questa è un'operazione concettualmente differente. Qui tu vuoi per creare una copia, e sembra che tu stia facendo bene. In C++ 11 potresti voler usare std::vector<T> myVector = std::move(myVector1) se tutto ciò che ti serve è trasferire il contenuto di myVector1 invece di copiarlo.

5.

std::vector<T>* myVector1 = new std::vector<T>; 
... (myVector1 being filled) 
std::vector<T> myVector = (*myVector1); 

Idem come sopra, si vuole Per creare una copia, ma si sta inutilmente allocare il vettore in modo dinamico. Questo di nuovo ti costringerà a prenderti cura della sua vita manualmente, che è cattiva e soggetta a errori. Non farlo.

6.

void myFunction(std::vector<T> myParam) { 
    ... 
} 

std::vector<T> myVector; 
... (myVector being filled) 
myFunction(myVector); 

Qui si sta passando myVector per valore. Se questo può essere ottimizzato dipende da cosa si suppone che myFunction abbia a che fare con il suo argomento: lo cambierà? In tal caso, vuoi che queste modifiche siano visibili dopo il ritorno dalla funzione? Se sì, passare per valore è corretto e non c'è modo di ottimizzarlo a meno che non sia a cui si desidera ottenere l'oggetto myVector: in tal caso, in C++ 11 è possibile spostare quando lo si passa alla funzione . Ciò eviterà una copia costosa e non necessaria.

7.

void myFunction(std::vector<T>& myParam) { 
    ... 
} 

std::vector<T> myVector; 
... (myVector being filled) 
myFunction(myVector); 

questo passerà per riferimento, ed è OK finché è bene vedere gli effetti collaterali di myFunction su myVector dopo il ritorno dalla funzione. Non si può dire in generale se ciò sia corretto o meno, dipende dalla particolare logica della tua applicazione.

+0

Grazie per la risposta dettagliata. Ho modificato il mio primo post relativo a 6 e 7: assumiamo che le modifiche apportate a 'myVector' all'interno di' myFunction' non danneggino il resto del programma, quindi passare per riferimento sarebbe sicuramente più veloce, giusto? – MrWayne

+0

@MrWayne: In tal caso, sì. Sarebbe più veloce. Potrebbe anche essere l'unico modo giusto se hai cambiato il tuo "non fare del male" in "deve essere visto da" –

Problemi correlati