ProgrammationDéveloppeur C++

Qu'est-ce que les itérateurs dans la STL C++, quels types existent et quelles nuances d'utilisation faut-il connaître en programmation ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse

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 :

  • InputIterator — pour lire une séquence vers l'avant.
  • OutputIterator — pour écrire des valeurs dans la séquence.
  • ForwardIterator — pour lire et écrire vers l'avant (vit plus longtemps que OutputIterator).
  • BidirectionalIterator — permet de se déplacer à la fois vers l'avant et vers l'arrière.
  • RandomAccessIterator — supporte l'accès aléatoire (par exemple, std::vector::iterator).

Une attention particulière doit être accordée à la durée de vie des itérateurs :

  • Les itérateurs des conteneurs peuvent devenir invalides (devenir non valides) lors de la modification du conteneur. Par exemple, l'insertion d'éléments dans un vecteur peut rendre les anciens itérateurs non valides.
  • Différents conteneurs gèrent différemment le cycle de vie des itérateurs. Dans std::list, l'insertion ou la suppression n'invalide pas les autres itérateurs, tandis que dans std::vector, cela invalide presque toujours.

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 piège

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 !

Exemples d'erreurs réelles dues à une méconnaissance des subtilités du sujet


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.