2012-01-13 16 views

risposta

218
std::fill(v.begin(), v.end(), 0); 
+30

Guardando l'output dell'assieme, gcc srotola questo loop in modo da utilizzare i registri mmx per eseguire il dump in 16 byte alla volta fino a quando non si avvicina alla fine. Direi che è piuttosto veloce. La versione di memset salta a memset, che immagino sia altrettanto veloce. Userò il tuo metodo – Omnifarious

+0

Tuttavia, saltare a memset è una singola istruzione, quindi utilizzarla comporterà una dimensione binaria più piccola. –

+0

questo non è esattamente quello che l'OP chiedeva, ma semplicemente riassegnare il tuo vettore a uno nuovo della stessa dimensione ('v = std :: vector (vec_size, 0)') sembra leggermente più veloce di 'fill' sulla mia macchina –

12

Se è solo un vettore di interi, mi piacerebbe provare prima:

memset(&my_vector[0], 0, my_vector.size() * sizeof my_vector[0]); 

Non è molto C++, quindi sono sicuro che qualcuno offrirà il modo corretto di fare questo. :)

+2

Dato che lo standard (2003 TC1) garantisce che un file std :: vector è contiguo nella memoria, questo dovrebbe andare bene. Se la libreria C++ non è conforme al TC1 2003, non utilizzare questo. – Mario

+2

@ Mario: Non avrei postato questo a meno che non fosse vero e presumibilmente noto, naturalmente. :) Ma grazie. – unwind

+1

Ho controllato il montaggio. Il metodo ':: std :: fill' si espande a qualcosa che è dannatamente veloce, anche se un po 'sul lato del codice dal lato in cui tutto è in linea. Lo userò comunque perché è molto più bello da leggere. – Omnifarious

2

provare

std::fill 

e anche

std::size siz = vec.size(); 
//no memory allocating 
vec.resize(0); 
vec.resize(siz, 0); 
+0

ridimensionare è molto bello – Nick

109

Come sempre quando si chiede circa più veloce: Misura! Utilizzando i metodi di cui sopra (su un Mac utilizzando Clang):

Method  | executable size | Time Taken (in sec) | 
      | -O0 | -O3 | -O0  | -O3  | 
------------|---------|---------|-----------|----------| 
1. memset | 17 kB | 8.6 kB | 0.125  | 0.124 | 
2. fill  | 19 kB | 8.6 kB | 13.4  | 0.124 | 
3. manual | 19 kB | 8.6 kB | 14.5  | 0.124 | 
4. assign | 24 kB | 9.0 kB | 1.9  | 0.591 | 

utilizzando 100000 iterazioni su un vettore di 10000 int.

Edit: Se changeing questi numeri plausibilmente muta i tempi risultanti si può avere un po 'di fiducia (non buono come ispezionare il codice di assemblaggio finale) che il parametro di riferimento artificiale non è stato ottimizzato via del tutto. Ovviamente è meglio messaggiare le prestazioni in condizioni reali. fine Modifica

di rinvio il codice utilizzato:

#include <vector> 

#define TEST_METHOD 1 
const size_t TEST_ITERATIONS = 100000; 
const size_t TEST_ARRAY_SIZE = 10000; 

int main(int argc, char** argv) { 

    std::vector<int> v(TEST_ARRAY_SIZE, 0); 

    for(size_t i = 0; i < TEST_ITERATIONS; ++i) { 
    #if TEST_METHOD == 1 
     memset(&v[0], 0, v.size() * sizeof v[0]); 
    #elif TEST_METHOD == 2 
     std::fill(v.begin(), v.end(), 0); 
    #elif TEST_METHOD == 3 
     for (std::vector<int>::iterator it=v.begin(), end=v.end(); it!=end; ++it) { 
     *it = 0; 
     } 
    #elif TEST_METHOD == 4 
     v.assign(v.size(),0); 
    #endif 
    } 

    return EXIT_SUCCESS; 
} 

Conclusione: uso std::fill (perché, come altri hanno detto il suo più idiomatica)!

+2

+1. Questo particolare benchmark non è conclusivo, ma il punto è assolutamente corretto, dovresti scrivere un test delle prestazioni delle alternative in quanto verranno effettivamente utilizzate. Se non vi è alcuna differenza di prestazioni, utilizzare quella che è la fonte più semplice. –

+1

"... non conclusivo ..." IMO questa inconcludenza di per sé è già un buon punto per fare benchmark, molto spesso l'Optimizer fa già un ottimo lavoro per il tipo di situazioni richieste dall'OP. E modificherei la tua ultima frase per leggere "Se non ci sono ** significative ** differenze di prestazioni ..." –

+1

Con "non conclusivo" intendevo che solo perché erano tutti della stessa velocità in questo programma non significa necessariamente avranno tutti la stessa velocità nel programma del questionario. A parte qualsiasi altra cosa, dovresti essere sicuro che la memoria sia effettivamente azzerata: potrebbe essere che l'ottimizzatore fosse abbastanza intelligente da ingannare il test. Ma dal momento che non hai il programma del questionario, non è una mancanza di questa risposta :-) E hai perfettamente ragione, è molto facile passare il tempo agonizzando per una scelta che in realtà non fa alcuna differenza (o una differenza insignificante) una volta ottimizzato. –

18

E la funzione membro assign?

some_vector.assign(some_vector.size(), 0); 
+0

L'OP voleva reimpostare i valori esistenti, ma la risposta è migliore quando si desidera ridimensionare _e resettare i valori. Grazie! –

0

Ho avuto la stessa domanda ma circa piuttosto breve vector<bool> (afaik standard consente di implementare internamente diverso che una schiera continua di elementi booleane). Quindi ho ripetuto le prove leggermente modificate di Fabio Fracassi. I risultati sono i seguenti (i tempi, in secondi):

  -O0  -O3 
     -------- -------- 
memset  0.666  1.045 
fill  19.357  1.066 
iterator 67.368  1.043 
assign 17.975  0.530 
for i  22.610  1.004 

Quindi, a quanto pare per queste dimensioni, vector<bool>::assign() è più veloce. Il codice utilizzato per le prove:

#include <vector> 
#include <cstring> 
#include <cstdlib> 

#define TEST_METHOD 5 
const size_t TEST_ITERATIONS = 34359738; 
const size_t TEST_ARRAY_SIZE = 200; 

using namespace std; 

int main(int argc, char** argv) { 

    std::vector<int> v(TEST_ARRAY_SIZE, 0); 

    for(size_t i = 0; i < TEST_ITERATIONS; ++i) { 
#if TEST_METHOD == 1 
     memset(&v[0], false, v.size() * sizeof v[0]); 
#elif TEST_METHOD == 2 
     std::fill(v.begin(), v.end(), false); 
    #elif TEST_METHOD == 3 
     for (std::vector<int>::iterator it=v.begin(), end=v.end(); it!=end; ++it) { 
      *it = 0; 
     } 
    #elif TEST_METHOD == 4 
     v.assign(v.size(),false); 
    #elif TEST_METHOD == 5 
     for (size_t i = 0; i < TEST_ARRAY_SIZE; i++) { 
      v[i] = false; 
     } 
#endif 
    } 

    return EXIT_SUCCESS; 
} 

ho usato GCC 7.2.0 del compilatore su Ubuntu 17.10. La riga di comando per la compilazione:

g++ -std=c++11 -O0 main.cpp 
g++ -std=c++11 -O3 main.cpp 
Problemi correlati