2013-04-29 10 views
14

Se sto utilizzando un iterator in un ciclo for e io uso erase su un'iterazione corrente di iteratore, per il ciclo dovrebbe continuare fine e accedere al resto degli elementi list?Cancellazione mentre l'iterazione di uno std :: list

Da quello che ho letto, questo dovrebbe essere il caso ed è una caratteristica di distinzione principale di list rispetto a deque o vector. Per i miei scopi, un queue potrebbe funzionare ma ho bisogno di questo comportamento.

Ecco il ciclo sto considerando:

std::list<Sequence>::iterator iterator; 
    iterator=m_concurrents.begin(); 
    for (;iterator!=m_concurrents.end();++iterator){ 
     if (iterator->passes()){ 
      m_concurrents.erase(iterator); 
     } 
    } 

risposta

43

Il modo idiomatico di scrivere quel ciclo sarebbe:

for (auto i = list.begin(); i != list.end();) { 
    if (condition) 
     i = list.erase(i); 
    else 
     ++i; 
} 

Puoi fare la stessa cosa con un set, multiset, map, o multimap. Per questi contenitori è possibile cancellare un elemento senza influire sulla validità di alcun iteratore su altri elementi. Altri contenitori come vector o deque non sono così gentili. Per quei contenitori, solo gli elementi prima dell'iteratore cancellato rimangono intatti. Questa differenza è semplicemente dovuta al fatto che gli elementi di archivio di list s in nodi allocati singolarmente. È facile prendere un link. vector s sono contigui, prendendo un elemento fuori muove tutti gli elementi dopo averlo indietro di una posizione.

Il ciclo è interrotto perché si cancella l'elemento su i in determinate condizioni. i non è più un iteratore valido dopo quella chiamata. Il ciclo for quindi incrementa i, ma i non è valido. L'inferno sulla terra segue. Questa è la situazione esatta per cui erase restituisce l'iteratore all'elemento dopo quello che è stato cancellato ... così puoi continuare a percorrere il list.

Si potrebbe anche usare list::remove_if:

list.remove_if([](auto& i) { return i > 10; }); 

Nel lambda, restituisce true se l'elemento deve essere rimosso. In questo esempio, rimuovere tutti gli elementi maggiori di 10.

+0

in questo esempio, si interrompe l'iterazione dopo che è stata cancellata, quindi non iterando l'elenco per rivedere potenzialmente altri elementi. Sono interessante nell'iterizzare l'intera lista e rimuovere le voci come desiderato. Da quello che ho capito, questo è sicuro con un 'elenco' ma non con altri contenitori. Questo è il cuore della mia domanda, mi dispiace se non è stato chiaro. – johnbakers

+2

Questo non funzionerà con i compilatori non C++ 11. I metodi dei membri cancellati restituiscono solo 'void' in C++ 03. Cambiando 'i = list.erase (i)' a 'list.erase (i ++)' lo aggiusterà. – Casey

+5

@Casey [ti sbagli] (http://en.cppreference.com/w/cpp/container/list/erase) – David

-1
for (auto i = list.begin(); i != list.end(); ++i) { 
    if (condition) { 
     list.erase(i); 
     --i; 
    } 
} 
Problemi correlati