Gültigkeit von Iteratoren bei zwischenzeitlichem Hinzufügen



  • Hallo zusammen,

    ich hab hier mal nen Beispiel gepostet. Hier verwende ich einen
    Iterator auf einem std::vector, füge neue Elemente hinzu und arbeite
    dann mit dem Iterator weiter. Es funktioniert allerdings nicht, da der
    std::vector sich irgendwann neuen Speicher alloziiert und der Inhalt
    nun woanders liegt und der Iterator auf dem vorherigen Bereich weiterarbeitet.

    #include <iostream>
    #include <vector>
    #include <list>
    
    int main(int argc, char *argv[]){
    	std::vector<int> vec;
    	for(int i=0; i<10; ++i){
    		vec.push_back(i);
    	}
    	std::vector<int>::const_iterator it = vec.begin();
    	for(int i=0; i<5; ++i){
    		int j = *it;
    		std::cout << j << std::endl;
    		++it;
    	}
    	for(int i=10; i<1000; ++i){
    		vec.push_back(i);
    	}
    	for(;it!=vec.end(); ++it){
    		std::cout << *it << std::endl;
    	}
    }
    

    Ich finde es auch sehr verständlich, warum das nicht geht.
    Meine Intuition sagt mir, dass es bei einer std::list klappt, da es sich
    ja um eine Verkettete Liste handelt. Es scheint auch zu funktionieren, aber
    kann ich mich darauf verlassen oder hab ich unter Umständen
    irgendwas zu befürchten?

    Wo ich den Beitrag gerade schreibe:
    Darf ich mir aus genau diesem Grund auch keine Referenz auf ein Objekt
    in einem Vektor dauerhaft halten?

    Gruß,
    *Cpp-Anfänger*



  • Die Referenz die ich nutze sagt zum Einfügen in lists:

    all of the previously obtained iterators and references remain valid after the insertion and refer to the same elements they were referring before.

    Und ja, Referenzen in einen vector werden genauso wie Iteratoren ungültig, sobald eine Einfügeoperation ein umkopieren der Inhalte des vectors nötig macht.



  • bei list ist dir garantiert, dass das einfügen keine iteratoren und/oder referenzen invalidiert, das löschen nur den jeweiligen iterator, der auf das zu löschende element zeigt.

    für vector ist das nur garantiert, wenn die anzahl der neuen elemente seine capacity vor dem einfügen nicht überschreitet. das heißt aber auch, dass deine iteratoren gültig bleiben, wenn du vor der initialisierung des iterators

    vec.reserve (vec.size() + 1000);
    std::vector<int>::const_iterator it = vec.begin();
    //...
    

    einfügst, wird dir auch nichts passieren.

    /edit: bei vector natürlich nur für einfügeoperationen und auch nur am ende des vectors garantiert.



  • Vielen Dank für eure prägnanten Erklärungen.

    Bisher hab ich Elemente immer mit

    list.push_back(i);
    

    ans Ende einer Liste angehängt.
    Hier steht sowas in dieser Referenz nicht
    explizit bei.
    In Zukunft werde ich wohl eher

    list.insert(list.end(),i);
    

    benutzen. Sicher ist sicher 🙂

    An di Möglichkeit der vorzeitigen Speicherreservierung für
    std::vectot hab ich auch gedacht, aber danke für die definitive
    Aussage.

    Ich wünsche euch noch einen schönen Heiligen Abend.


Anmelden zum Antworten