Les itérateurs sont des objets qui permettent de faire référence aux éléments des conteneurs STL comme des pointeurs. Ils fournissent un moyen unifié d'accès aux éléments de n'importe quel conteneur (vector, list, map, etc.). Les itérateurs existent sous plusieurs formes :
Une attention particulière doit être accordée à la durée de vie des itérateurs :
Exemple :
std::vector<int> v = {1,2,3,4,5}; for (auto it = v.begin(); it != v.end(); ++it) { if (*it == 3) { // Suppression de l'élément de valeur 3 it = v.erase(it); // erase retourne l'itérateur vers l'élément suivant --it; // ajuster l'itérateur si nécessaire } }
Question : Lors de l'appel de std::vector::insert, les itérateurs deviennent-ils invalides ?
Réponse fréquente : Non, uniquement lors de l'ajout en dehors de la plage de fin.
Réponse correcte : Tous les itérateurs et références égales ou suivant la position d'insertion deviennent invalides si la capacité du conteneur augmente. Si la capacité est suffisante, seuls les itérateurs dans la plage après le point d'insertion deviennent invalides.
Exemple :
std::vector<int> v = {1,2,3}; auto it = v.begin() + 1; v.insert(v.begin(), 0); // it pourrait ici devenir invalide !
Histoire : Dans un projet, des pointeurs étaient utilisés pour itérer sur std::vector, et après push_back, l'itération se poursuivait sur des pointeurs invalides, ce qui entraînait un plantage de l'application.
Histoire : Un développeur supprimait des éléments de std::list via erase dans une boucle for(auto it : list), sans utiliser l'itérateur retourné par erase, ce qui entraînait des sauts d'éléments et des suppressions d'éléments incorrects.
Histoire : Du code utilisait std::map, et après erase par clé, l'itérateur restait lié à l'élément supprimé (comportement indéfini) — ce qui entraînait des plantages aléatoires lors des accès ultérieurs.