Iteratoren sind Objekte, die es ermöglichen, auf Elemente von STL-Containern ähnlich wie auf Zeiger zuzugreifen. Sie bieten einen vereinheitlichten Zugang zu den Elementen beliebiger Container (vector, list, map usw.). Iteratoren gibt es in mehreren Arten:
Besondere Aufmerksamkeit sollte der Lebensdauer von Iteratoren gewidmet werden:
Beispiel:
std::vector<int> v = {1,2,3,4,5}; for (auto it = v.begin(); it != v.end(); ++it) { if (*it == 3) { // Entfernen des Elements mit dem Wert 3 it = v.erase(it); // erase gibt den Iterator auf das nächste Element zurück --it; // falls nötig, den Iterator anpassen } }
Frage: Invalidate Iteratoren bei Aufruf von std::vector::insert?
Häufige Antwort: Nein, nur beim Hinzufügen außerhalb des Endes.
Richtige Antwort: Alle Iteratoren und Referenzen, die gleich oder nach der Einfügeposition sind, werden ungültig, wenn die Kapazität des Containers erhöht wird. Wenn jedoch die Kapazität ausreicht, werden nur die Iteratoren im Bereich nach dem Einfügepunkt ungültig.
Beispiel:
std::vector<int> v = {1,2,3}; auto it = v.begin() + 1; v.insert(v.begin(), 0); // it könnte hier ungültig werden!
Geschichte: In einem Projekt wurden Zeiger zur Iteration über std::vector verwendet, und nach dem push_back setzte sich die Iteration über ungültige Zeiger fort, was zum Absturz der Anwendung führte.
Geschichte: Ein Entwickler entfernte Elemente aus std::list über erase in einer Schleife (for(auto it : list)), ohne den zurückgegebenen erase-Iterator zu verwenden, wodurch die Iteration über Elemente sprang und nicht alle benötigten entfernt wurden.
Geschichte: Im Code wurde std::map verwendet, und nach erase über den Schlüssel blieb der Iterator an das entfernte Element gebunden (undefiniertes Verhalten) — dies führte zu zufälligen Abstürzen bei weiteren Zugriffen.