Domanda

Quale dei seguenti è migliore e perché?(Particolarmente c++)

UN.

int i(0), iMax(vec.length());//vec is a container, say std::vector
for(;i < iMax; ++i)
{
  //loop body
}

B.

for( int i(0);i < vec.length(); ++i)
{
  //loop body
}

Ho visto consigli per (a) a causa della funzione di chiamata alla lunghezza.Questo mi dà fastidio.Nessun compilatore moderno esegue l'ottimizzazione di (b) in modo che sia simile a (a)?

È stato utile?

Soluzione

L'esempio (b) ha un significato diverso dall'esempio (a) e il compilatore deve interpretarlo mentre lo scrivi.

Se, (per qualche motivo inventato a cui non riesco a pensare), ho scritto un codice per farlo:

for( int i(0);i < vec.length(); ++i)
{
    if(i%4 == 0)
       vec.push_back(Widget());
}

Non avrei davvero voluto che il compilatore ottimizzasse ogni chiamata a vec.length (), perché avrei ottenuto risultati diversi.

Altri suggerimenti

Mi piace:

for (int i = 0, e = vec.length(); i != e; ++i)

Naturalmente, questo funzionerebbe anche per gli iteratori:

for (vector<int>::const_iterator i = v.begin(), e = v.end(); i != e; ++i)

Mi piace perché è sia efficiente (chiamando end() solo una volta), sia relativamente conciso (è necessario digitare vector<int>::const_iterator una volta).

Sono sorpreso che nessuno abbia detto l'ovvio:

Nel 99,99% dei casi, non importa.

A meno che non si stia utilizzando un contenitore in cui il calcolo size() è un'operazione costosa, è insondabile che il programma rallenti di alcuni nanosecondi. Direi di rimanere più leggibile fino a quando non profilerai il tuo codice e scoprirai che <=> è un collo di bottiglia.

Ci sono due questioni da discutere qui:

  1. L'ambito variabile
  2. Nuova valutazione della condizione finale

Ambito variabile

Normalmente, non è necessario che la variabile loop sia visibile al di fuori del loop. Ecco perché puoi dichiararlo all'interno del for costrutto.

Rivalutazione delle condizioni finali

Andrew Shepherd lo ha affermato bene: significa qualcosa di diverso inserire una chiamata di funzione all'interno della condizione finale:

for( vector<...>::size_type i = 0; i < v.size(); ++i ) { // vector size may grow.
   if( ... ) v.push_back( i ); // contrived, but possible
}

// note: this code may be replaced by a std::for_each construct, the previous can't.
for( vector<...>::size_type i = 0, elements = v.size(); i != elements; ++i ) {
}

Perché ti sta dando fastidio? Queste due alternative non vedono di fare lo stesso. Uno sta eseguendo un numero fisso di iterazioni, mentre l'altro dipende dal corpo dei loop.

Un'altra alternativa potrebbe essere

for (vector<T>::iterator it=vec.begin();it!=vec.end();it++){
 //loop body
}

A meno che non sia necessaria la variabile loop al di fuori del loop, è preferibile il secondo approccio.

Gli Iteratori ti daranno effettivamente prestazioni migliori o migliori. (C'è stato un grosso thread di confronto su comp.lang.c ++. Moderato qualche anno fa).

Inoltre, userei

int i = 0;

Piuttosto che il costruttore come la sintassi che stai usando. Sebbene valido, non è idiomatico.

Un po 'estraneo:

Avviso: confronto tra intero con segno e senza segno.

Il tipo corretto per gli indici di array e vettoriali è size_t.

A rigor di termini parlando, in C ++ è persino std::vector<>::size_type.

Incredibile quanti sviluppatori C / C ++ continuano a sbagliare.

Vediamo sul codice generato (utilizzo MSVS 2008 con ottimizzazione completa).

a.

int i(0), iMax(vec.size());//vec is a container, say std::vector
for(;i < iMax; ++i)
{
  //loop body
}

Il ciclo for produce 2 istruzioni assembler.

b.

for( int i(0);i < vec.size(); ++i)
{
  //loop body
}

Il ciclo for produce 8 istruzioni assembler. vec.size () è stato inserito correttamente.

c.

for (std::vector<int>::const_iterator i = vec.begin(), e = vec.end(); i != e; ++i)
{
  //loop body
}

Il ciclo for produce 15 istruzioni assembler (tutto è in linea, ma il codice ha molti salti)

Quindi, se la tua applicazione è critica per le prestazioni usa a). Altrimenti b) oc).

Va notato che gli esempi di iteratori:

for (vector<T>::iterator it=vec.begin();it!=vec.end();it++){
 //loop body
}

potrebbe invalidare l'iteratore del ciclo "it" nel caso in cui il corpo del ciclo dovesse causare la riallocazione del vettore.Quindi non è equivalente a

for (int i=0;i<vec.size();++i){
 //loop body
}

dove il corpo del ciclo aggiunge elementi a vec.

Domanda semplice: stai modificando vec nel ciclo?

la risposta a questa domanda porterà anche alla tua risposta.

JRH

È molto difficile per un compilatore sollevare la chiamata vec.length() con la certezza che è costante, a meno che non sia in linea (cosa che speriamo spesso lo faccia!). Ma almeno i dovrebbe sicuramente essere dichiarato nel secondo stile & Quot; b & Quot ;, anche se la chiamata length deve essere & Quot; manualmente & Quot; issato fuori dal giro!

Questo è preferibile:

typedef vector<int> container; // not really required,
                               // you could just use vector<int> in for loop

for (container::const_iterator i = v.begin(); i != v.end(); ++i)
{
    // do something with (*i)
}
  • Posso dire subito che il vettore non viene aggiornato
  • chiunque può dire cosa sta succedendo qui
  • So quanti loop
  • v.end() restituisce il puntatore oltre il ultimo elemento, quindi non ci sono spese generali di controllo dimensioni
  • facile da aggiornare per diversi contenitori o tipi di valore

(b) non calcolerà / chiamerà la funzione ogni volta.

- inizia estratto ----

Movimento del codice invariante di loop: GCC include il movimento del codice invariante di loop come parte del suo ottimizzatore di loop e nel suo passaggio di eliminazione della ridondanza parziale. Questa ottimizzazione rimuove le istruzioni dai loop, che calcolano un valore che non cambia durante il ciclo di vita di un loop.

--- fine estratto -

Altre ottimizzazioni per gcc:

https://www.in.redhat.com/software /gnupro/technical/gnupro_gcc.php3

Perché non eludere completamente il problema con BOOST_FOREACH

#include <boost/foreach.hpp>

std::vector<double> vec;

//...

BOOST_FOREACH( double &d, vec)
{
    std::cout << d;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top