Perché usare classic for loops come iteratori in stl considerati pessimi?

3

Ho letto un paio di articoli ( esempio ) che considerano il classico

for (int ...... size() .... i++) pratica cattiva del ciclo durante l'iterazione, ad esempio, dei vettori in stl. Invece il motivo raccomandato è usare gli iteratori di vettori, cioè begin, end , ecc.

Perché?

    
posta Karlth 01.01.2013 - 16:14
fonte

4 risposte

10

Se sai che stai operando su std::vector , e questo non cambierà mai, non c'è niente di fondamentalmente sbagliato in quella forma di for loop - è ben compreso, facile da leggere, e il compilatore di solito fa un buon lavoro per eliminare il costo potenziale di chiamare size() su ogni ciclo.

Ma usare un ciclo for con iteratori è più generico. Non richiede affatto che il tuo contenitore abbia un operatore size() , e non richiede che il contenitore abbia accessors basati su indici (per non parlare di quelli efficienti). Quindi il tuo codice sarà più generico se segui questa strada.

Altre cose da considerare in questi giorni:

risposta data 01.01.2013 - 16:41
fonte
9

Il più delle volte, entrambi riguardano pratiche altrettanto cattive.

Quello che dovresti normalmente provare a fare è capire cosa realizza il ciclo, e usare un algoritmo esistente o scrivere un nuovo algoritmo per compiere genericamente quel fine, quindi applicare quell'algoritmo alla raccolta / gamma a portata di mano.

Per esempio, supponiamo che stavi sommando gli elementi in un vettore:

int total = 0;

for (int i=0; i<v.size(); i++)
    total += v[i];

std::cout << "Total = " << total << "\n";

Riscrivere questo per usare gli iteratori non è sostanzialmente un miglioramento (e probabilmente dannoso):

int total = 0;

for (std::vector<int>::iterator p = v.begin(); p!= v.end(); ++p)
    total += *p;

std::cout << "Total = " << total << "\n";

Usando C ++ 11, puoi almeno ripristinare un piccolo equilibrio:

int total = 0;

for (auto p : v)
    total += p;

std:cout << "Total = " << total << "\n";

... ma non hai nemmeno bisogno del C ++ 11 per farlo ancora meglio:

std::cout << "Total = " 
          << std::accumulate(v.begin(), v.end(), 0)
          << "\n";

Quando ti ritrovi a pensare a scrivere un ciclo, cambiare il loop per usare un iteratore è raramente la risposta giusta - la risposta giusta è di solito eliminare il ciclo e sostituirlo con un algoritmo .

    
risposta data 01.01.2013 - 23:56
fonte
1

Non direi che è una cattiva pratica, direi che usare un iteratore come migliore pratica.

Perché? Perché è più esplicito. Con un ciclo normale non si utilizza necessariamente ogni elemento, si potrebbe eseguire un'operazione correlata, ma non direttamente connessa. Ad esempio, un programma di noleggio di gruppo potrebbe prenotare il numero X di biglietti perché ha un gruppo di dimensioni X, in cui l'assegnazione del biglietto avviene in una fase successiva.

Usando l'iteratore si dice che si sta andando oltre la collezione e facendo qualcosa con ogni elemento. Trasmette meglio l'intento del programma.

    
risposta data 01.01.2013 - 17:31
fonte
0

Dipende dall'implementazione della collezione. Alcune raccolte non hanno un modo rapido e pronto per determinare il numero di elementi che contengono. Per queste raccolte, chiamare size() può richiedere una completa iterazione attraverso la raccolta solo per dirti quanti ce ne sono. Tali raccolte potrebbero non avere un semplice meccanismo per l'accesso casuale.

Ad esempio, una raccolta di "linee in un file di testo" richiederebbe l'analisi dell'intero file di testo solo per trovare il numero di linee in esso contenute. Se stai solo scrivendo un loop per trovare una riga nel file, in realtà non ti importa di quante linee ha il file, è necessario solo costruire un loop in questo modo.

Tale raccolta può ancora essere ottimizzata per funzionare bene senza capacità di accesso casuale. Le ipotetiche "linee in un file di testo" possono facilmente darti ogni riga, in ordine, in modo rapido ed efficiente. L'oggetto Iterator mantiene la posizione corrente e sa come ottenere il valore successivo, ma nessuno ha dovuto creare un indice di tutte le posizioni iniziali di tutte le righe nel file.

In sintesi, l'approccio iteratore consente di iterare tali raccolte senza dover sapere in anticipo quanti elementi ci sono e senza bisogno di un metodo di accesso casuale veloce.

    
risposta data 01.01.2013 - 17:47
fonte

Leggi altre domande sui tag