HOWTO · C++
Itérer dans une liste en C++
Il s'agit d'un didacticiel simple sur la structure de données List et sur la façon dont nous pouvons parcourir la structure de données List en C++.
Sur cette page
Pour parcourir une std::list en C++, initialisez un itérateur avec begin(), poursuivez tant qu’il est différent de end(), puis incrémentez-le après avoir traité chaque élément. Déréférencez l’itérateur pour lire ou modifier la valeur courante. La boucle s’arrête avant end(), qui marque la position située après le dernier élément et ne désigne pas un itérateur vers celui-ci.
Qu’est-ce que std::list en C++ ?
std::list est le conteneur de liste doublement chaînée de la bibliothèque standard C++. Ses éléments sont stockés dans des nœuds reliés à leurs voisins : ils ne se trouvent donc pas dans un bloc mémoire contigu comme les éléments d’un std::vector ou d’un tableau. Cette structure permet de parcourir la liste dans les deux sens et d’insérer ou de supprimer un élément en temps constant lorsque vous disposez déjà d’un itérateur vers sa position.
Une liste ne permet pas l’accès direct par indice, comme items[4]. Pour atteindre un élément à une position donnée, il faut avancer un itérateur dans la liste ; le temps nécessaire est proportionnel à la distance parcourue. Chaque élément nécessite également de l’espace supplémentaire pour stocker ses liens. Choisissez std::list lorsque la stabilité des itérateurs et l’insertion ou la suppression à des positions connues sont utiles. Un vecteur est souvent plus simple si vous avez besoin d’un stockage compact ou d’un accès fréquent par indice.
C++ fournit aussi std::forward_list, un conteneur distinct à chaînage simple qui ne permet le parcours que dans un sens. Ce n’est pas le même conteneur que std::list. Pour en savoir plus, consultez l’article sur les listes doublement chaînées.
Comment parcourir une std::list en C++
L’itérateur renvoyé par begin() désigne le premier élément. end() désigne la position juste après le dernier élément : il sert donc de condition d’arrêt de la boucle et ne doit pas être déréférencé. Incrémenter l’itérateur le fait avancer jusqu’à l’élément suivant.
Exécutez cet exemple :
Le code et les libellés ou sorties affichés dans cette section restent en anglais.
#include <iostream>
#include <list>
int main() {
std::list<int> scores{12, 18, 25};
for (std::list<int>::iterator it = scores.begin(); it != scores.end(); ++it) {
std::cout << *it << '\n';
}
}
12
18
25
Ici, it commence à scores.begin(). À chaque passage, l’expression *it lit la valeur courante, puis ++it fait avancer l’itérateur jusqu’au nœud suivant. Lorsque l’itérateur atteint scores.end(), la condition devient fausse et la boucle se termine sans lire la position située après le dernier élément. La sortie de l’exemple affiche 12, 18 et 25.
Vous pouvez modifier un élément avec un itérateur non constant en affectant une valeur à *it. Par exemple, dans le corps de la boucle, *it += 1; augmente la valeur courante. Utilisez une boucle for basée sur une plage si vous avez seulement besoin de parcourir les valeurs : for (int score : scores). Pour les modifier dans cette forme, liez chaque élément par référence : for (int& score : scores). Préférez la boucle explicite avec itérateur lorsque vous avez besoin de l’itérateur lui-même, par exemple pour supprimer l’élément courant.
Lors d’une suppression pendant le parcours, affectez à l’itérateur la valeur renvoyée par erase afin de reprendre sur l’élément suivant. La suppression invalide l’itérateur vers l’élément supprimé, mais les itérateurs vers les autres éléments de std::list restent valides.