2013-04-23 9 views
6

Il seguente codice funziona come previsto (il test passa) ma mi chiedo se lavorare con gli iteratori in questo modo sia considerato una cattiva pratica in C++ o se va bene.Aggiunta di un std :: vector con i propri elementi utilizzando gli iteratori

Forse questo è specifico per std::vector e altre raccolte si comportano in modo diverso e le migliori pratiche variano tra le raccolte (o anche le loro implementazioni)?

Non va bene in altre lingue e il più delle volte la modifica di una raccolta invalida gli iteratori e genera eccezioni.

BOOST_AUTO_TEST_CASE (ReverseIteratorExample) { 
    std::vector<int> myvector; 
    for(int i = 0; i < 5; i++) 
    { 
     myvector.push_back(i); 
    } 

    // is this generally a bad idea to change the vector while iterating? 
    // is it okay in this specific case? 
    myvector.reserve(myvector.size() + myvector.size() - 2); 
    myvector.insert(myvector.end(), myvector.rbegin() + 1, myvector.rend() -1); 

    int resultset [8] = { 0,1,2,3,4,3,2,1 }; 
    std::vector<int> resultVector(resultset, resultset + sizeof(resultset)/sizeof(resultset[0])); 
    BOOST_CHECK_EQUAL_COLLECTIONS(myvector.begin(), myvector.end(), resultVector.begin(), resultVector.end()); 
} 

Domande illustrati:

  1. È questo in generale una cattiva idea di cambiare il vettore, mentre l'iterazione?
  2. Va bene in questo caso specifico?
  3. È specifico per std::vector e altre raccolte si comportano in modo diverso?
  4. Le best practice variano tra le raccolte (o anche le loro implementazioni)?
+0

c'è questo veramente interessante domanda SO e le sue risposte, a cui ho sempre si riferiscono a in caso di dubbio: http://stackoverflow.com/questions/4114503/rules-for-iterator-invalidation Essa elenca container standard C++ e il caso in cui gli iteratori sono invalidati o ancora validi. (che risponde ai punti 3. e 4.) –

+0

Riguardo al n. 4: utilizzare 'std :: list' – TemplateRex

risposta

12

Questo non è un codice valido. La definizione del livello di operazioni sui contenitori di sequenza afferma ([email protected]):

a.insert (p, i, j) - [...] pre: i e j non sono iteratori in una.

Così il tuo codice richiama un comportamento indefinito perché viola il presupposto per l'operazione insert.

Se invece di usare insert, è scritto un loop iterare myvector.rbegin() + 1-myvector.rend() -1 e chiamato push_back su tutti i valori, il codice sarebbe valida: Questo perché push_back invalida solo iteratori vettore se è necessaria una riallocazione, e la chiamata a reserve assicura che questo non sia il caso.

In generale, mentre alcuni casi in cui la modifica di un contenitore durante l'iterazione è soddisfacente (come il ciclo descritto sopra), è necessario assicurarsi che gli iteratori non vengano invalidati durante tale operazione. Quando ciò accade è specifico per ogni contenitore.

+0

per le regole di convalida iteratore specifiche del contenitore vedere questa [domanda] (http://stackoverflow.com/questions/6438086/iterator -invalidation-rules? lq = 1) – TemplateRex

+0

Grazie per la risposta. Peccato che sembra funzionare comunque. Lo aggiungerò alla mia lista di cose che odio di C++. – tobsen

Problemi correlati