2009-03-06 13 views
5

Ho una domanda sullo std :: vector.Pulisci il vettore ogni iterazione del ciclo. Qual è il modo più efficiente di memoria?

Ho un algoritmo molto intensivo di memoria in cui prevedo che prevedere le dimensioni dei vettori e riservare abbastanza memoria per i vettori in anticipo mi aiuterà molto a ridurre l'utilizzo della memoria.

Quale dei seguenti è meglio:

for (...) { 
    std::vector<Type> my_vector; 
    my_vector.reserve(stuff_count); 
    // Do stuff , and append stuff to my_vector. 
} 

O questo:

std::vector my_vector; 
for (...) { 
    my_vector.clear(); 
    my_vector.reserve(stuff_count); 
    // Do stuff , and append stuff to my_vector. 
} 

La prego di dirmi che è meglio, o se c'è un modo migliore di fare le cose.

Grazie mille in anticipo!

+0

Questa non è una domanda di tipo opinione. Dovresti misurare la differenza per il tuo particolare sistema. –

risposta

11

Con la prima variante si rialloca il buffer del vettore su ogni iterazione, che di solito è piuttosto costoso. Con la seconda variante si rialloca solo occasionalmente. La seconda variante è migliore poiché la velocità è una priorità per te.

Non è chiaro da voi la domanda da dove il numero di elementi è noto. Forse si può anche calcolare rapidamente il numero massimo di elementi per tutte le iterazioni, impostare come dimensione del buffer e non avere riallocazione.

+0

che di solito è piuttosto costoso: questa è una dichiarazione audace senza profilazione. L'allocatore di memoria C++ è progettato proprio per questo tipo di situazione, quindi ne dubito (ma anche questa affermazione è audace e deve essere testata). –

+0

Bene, una volta dovevamo fare il profilo in una situazione simile. Tali riallocazioni in casi estremi erano responsabili per circa il 95% del tempo - un buffer è stato allocato, i dati sono stati copiati, analizzati brevemente e quindi il buffer è stato scartato. È stato piuttosto sorprendente. – sharptooth

+0

Questo porta alla conclusione che se si desidera una rapida esecuzione dovrebbe evitare inutili riallocazioni. – sharptooth

5

Il secondo potrebbe essere leggermente più veloce, ma trovo il primo pulitore.

+0

Clean è ok, ma nella mia situazione, clean non ha importanza in quanto il mio algoritmo ha bisogno dell'ottimizzazione possibile. I miei test non ottimizzati potrebbero utilizzare memoria da 10 GB senza problemi. – Nailer

+0

Quindi non dovresti fare domande come questa (l'opinione di tutti può sbagliare molto/molto). Quello che dovresti fare è profilare il codice e cronometrarlo su un set di dati più piccolo. –

5

Poiché le differenze nel codice sono banali, perché non testare entrambi gli approcci e vedere quale funziona meglio per la particolare applicazione?

1

Dipende un po 'da come il Tipo deve essere costruito/distrutto, direi. Se è un POD che non richiede distruzione, è possibile saltare la chiara(), che chiama tutti i distruttori in un ciclo, e usarlo come una matrice statica invece:

std::vector<Type> my_vector(size); 
for (...) 
{ 
    int index = 0; 
    // Do stuff 
    my_vector[index] = some_value; 
} 

(Caveat: codice non testato)

+0

Se si tratta di un POD, mi aspetto che il vettore ottimizzi comunque la distruzione. Provalo prima di saltare alle conclusioni sulle prestazioni – jalf

+0

concordato. (con Jalf) –

+0

In teoria, hai ragione, jalf. Considera la mia risposta come un suggerimento che potresti distruggere molto le cose e che probabilmente c'è del lavoro che può essere fatto lì. –

1

... riservare memoria sufficiente per le vettori in anticipo mi aiuterà molto con la riduzione dell'utilizzo della memoria

err ... cosa ?! Non ha assolutamente senso. La prenotazione della memoria non aiuta a ridurre l'utilizzo della memoria in alcun modo. Impedisce la necessità di una riallocazione costante che rende le cose più veloci, ma per quanto riguarda l'utilizzo di non si ottiene alcun beneficio.

+0

In effetti il ​​numero di byte liberi sarà uguale, ma il chunk più grande allocabile sarà più piccolo: riallocando più e più volte fino a quando non si ottiene la giusta dimensione si frammenterà infine l'heap. Alla fine. – xtofl

+0

Inoltre, i vettori devono avere memoria continua, quindi se il vettore corrente non può più essere esteso, è necessario allocare un blocco completamente nuovo, il vecchio vettore copiato e deallocato. Memoria che utilizza temporaneamente (oldsize + newsize). Se hai enormi requisiti di memoria, diventa rilevante. – Pieter

+0

I vettori assegnano il doppio della memoria di cui hanno bisogno quando si chiama la funzione append e non c'è spazio sufficiente per l'elemento successivo. Ciò significa che se ho un vettore abbastanza grande per 100 elementi, quando aggiungo l'elemento 101st il vettore allocherà memoria sufficiente per 200 elementi. – Nailer

6

Vedo che predire le dimensioni dei vettori e riservare abbastanza memoria per i vettori in anticipo mi aiuterà molto a ridurre l'utilizzo della memoria.

Cerca di comportarti come un ingegnere e non come un indovino. Crea un test e misura la differenza.

0

Se è necessario eseguire molti accodamenti, utilizzare std :: deque anziché std :: vector e utilizzare semplicemente "push_back".

0

che ne dici?

std::vector<DataType> my_vector; 
my_vector.resize(sizeof(yourData)); 
memcpy(reinterpret_cast<char*>(&my_vector), &yourData, sizeof(yourData)); 
+0

Perché non std :: copy()? –

1

La seconda userà la memoria massima di tutti gli usi di essa attraverso l'anello, cioè la dimensione massima dei tipi di stuff_count. std::vector::clear() does not necessarily free memory. Ad esempio, se si chiama std::vector::capacity() prima e dopo std::vector::clear(), un'implementazione conforme standard potrebbe restituire lo stesso valore.

Nella migliore delle ipotesi, si riduce il numero di volte che si alloca memoria con lo schema precedente. Ma certamente non ridurrai l'impronta della memoria in nessun punto. Se si desidera ridurre la quantità riservata della memoria, è necessario utilizzare l'idioma vettore swap:

std::vector<type>().swap(my_vector); 
my_vector.reserve(stuff_count); 

O il vostro prima soluzione, dal momento che l'effetto complessivo sarà lo stesso.

Problemi correlati