Iterators zijn objecten die verwijzen naar de elementen van STL-containers, vergelijkbaar met pointers. Ze bieden een geüniformeerde manier van toegang tot de elementen van elke container (vector, list, map, enz.). Er zijn verschillende soorten iterators:
Bijzondere aandacht moet worden besteed aan de levensduur van iterators:
Voorbeeld:
std::vector<int> v = {1,2,3,4,5}; for (auto it = v.begin(); it != v.end(); ++it) { if (*it == 3) { // Verwijder het element met waarde 3 it = v.erase(it); // erase retourneert een iterator naar het volgende element --it; // indien nodig iterator aanpassen } }
Vraag: Worden iterators ongeldig bij het aanroepen van std::vector::insert?
Veelvoorkomend antwoord: Nee, alleen bij het toevoegen buiten het bereik van het einde.
Juiste antwoord: Alle iterators en referenties die gelijk zijn aan of volgen na de invoegpositie worden ongeldig, indien de capaciteit van de container toeneemt. Als de capaciteit voldoende is, worden alleen de iterators in het bereik na het invoegpunt ongeldig.
Voorbeeld:
std::vector<int> v = {1,2,3}; auto it = v.begin() + 1; v.insert(v.begin(), 0); // it kan hier ongeldig worden!
Verhaal: In een project werden pointers gebruikt om door std::vector te itereren, en na push_back ging de iteratie verder met ongeldig geworden pointers, wat leidde tot een crash van de applicatie.
Verhaal: Een ontwikkelaar verwijderde elementen van std::list met erase in een for(auto it : list) lus, zonder de geretourneerde erase iterator te gebruiken, waardoor de iteratie sprongen maakte over elementen en niet alle benodigde elementen werden verwijderd.
Verhaal: In de code werd std::map gebruikt, en na erase op de sleutel bleef de iterator gekoppeld aan het verwijderde element (undefined behavior) — dit leidde tot willekeurige crashes bij verdere toegang.