Les itérateurs en C++ - définition, déclaration et exemples
Un itérateur est tout comme un pointeur, il est en fait une abstraction d'un pointeur. Les itérateurs sont utilisés pour passer d'un élément à un autre, un processus connu sous le nom d'itération dans le conteneur.
Un itérateur est une classe qui a comme données membres un pointeur et des opérations prédéfinies qui peuvent être appliquées à ce pointeur.
Un avantage d'un itérateur par rapport à un pointeur est que nous ne pouvons pas limiter les opérations définies pour un pointeur, ni augmenter les opérations définies pour un pointeur. Mais nous pouvons faire les deux pour un itérateur. Par exemple, nous pouvons définir un itérateur qui ne peut qu'avancer en incluant l'opérateur ++ et en excluant l'opérateur --. Nous pouvons définir un itérateur qui ne peut pas passer d'un objet à un autre dans un conteneur en ne définissant pas l'opérateur plus (+) ou moins (-) pour la classe. Nous pouvons dire qu'un itérateur ne peut qu'accéder à un élément ou ne peut que modifier un élément, ou peut faire les deux.
Un autre avantage d'un itérateur est qu'il peut masquer la structure interne d'un conteneur. Chaque conteneur peut définir son propre type d'itérateur dont la conception est cachée à l'utilisateur, mais l'utilisateur peut créer un itérateur de ce type et accéder aux objets du conteneur.
Types d'itérateurs
Nous pouvons classer les itérateurs en cinq types : itérateur d'entrée, itérateur de sortie, itérateur avant, itérateur bidirectionnel et itérateur à accès aléatoire, comme le montre la figure ci-dessous.
Itérateur d'entrée
Un itérateur d'entrée peut utiliser l'opérateur de déréférencement uniquement pour lire à partir d'un conteneur ; il n'est pas permis d'y écrire. En d'autres termes, un itérateur d'entrée traite le conteneur comme une source d'éléments de données à lire.
Itérateur de sortie
Un itérateur de sortie peut utiliser l'opérateur de déréférencement pour écrire uniquement dans un conteneur ; il n'est pas autorisé à lire à partir de celui-ci.
Itérateur avant
Un itérateur vers l'avant peut lire ou écrire des éléments. Sa fonctionnalité est la combinaison des itérateurs d'entrée et de sortie.
Itérateur bidirectionnel
Un itérateur bidirectionnel peut se déplacer dans les deux sens : vers l'arrière et vers l'avant. Les opérateurs ++ et −− sont définis pour cet itérateur.
Itérateur à accès aléatoire
Un itérateur à accès aléatoire a les capacités d'un itérateur bidirectionnel, et en plus, il prend en charge l'opérateur d'addition (+) et l'opérateur de soustraction (-). Il fournit également quatre opérateurs relationnels (<, <=, > et >=) qui ne sont pas fournis par les autres itérateurs. Ces opérateurs nous permettent d'utiliser l'opérateur d'index [], qui nécessite les opérateurs +, - et opérateurs relationnels pour un mouvement vers l'avant ou vers l'arrière.
Itérateur | Sens du mouvement | Lecture | Ecriture | * | ++ | -- | == et =! | <, <=,>, >= | + et - |
---|---|---|---|---|---|---|---|---|---|
Itérateur d'entrée | En avant seulement | ||||||||
Itérateur de sortie | En avant seulement | ||||||||
Itérateur avant | En avant seulement | ||||||||
Itérateur bidirectionnel | En avant et en arrière | ||||||||
Itérateur à accès aléatoire | En avant et en arrière |
Un conteneur définit normalement deux catégories d'itérateurs : régulier (appelé iterator) et inverse (appelé reverse_iterator). Les directions de déplacement de ces deux types d'itérateurs sont illustrées dans la figure ci-dessous.
Dans un itérateur régulier, les opérateurs ++ et + signifient se déplacer vers l'arrière ; les opérateurs −− et − signifient se déplacer vers l'avant. Dans un itérateur inverse, les opérateurs ++ et + signifient se déplacer vers l'avant ; les opérateurs −− et − signifient se déplacer vers l'arrière.
Fournisseurs d'itérateurs
Itérateur | Fournisseur (classe) |
---|---|
Itérateur d'entrée | istream |
Itérateur de sortie | ostream |
Itérateur avant | |
Itérateur bidirectionnel | List, set, multiset, map, multimap |
Itérateur à accès aléatoire | Vector, deque, array |
Opérations sur les itérateurs
Les classes conteneurs fournissent de nombreuses opérations pour manipuler les itérateurs :
begin
Cette fonction renvoie un itérateur pointant sur le premier élément du conteneur. Si la séquence est vide, la valeur renvoyée ne doit pas être déréférencée.
end
Cette fonction renvoie un itérateur pointant sur l'élément après le dernier élément du conteneur. Si la séquence est vide, la valeur renvoyée est égale à celle renvoyée par begin avec le même argument.
Exemple 1
#include<iostream> #include<string> #include<iterator> // classe itérateur #include<vector> // classe vecteur (conteneur) using namespace std; int main ( ){ // définir un vecteur vector<string> jrs = {"Lundi", "Mardi", "Mercredi","Jeudi", "Vendredi", "Samedi","Dimanche" }; cout<< "Le premier element est : "<< *std::begin(jrs); cout<< '\n'; // Afficher des éléments à l'aide de begin() et end() vector<string>::iterator it; cout << "Les jours par begin() et end() : "<<endl;; for (it = std::begin(jrs); it < std::end(jrs); it++) cout << *it << " \t"; return 0; }
Résultat
Le premier element est : Lundi Les jours par begin() et end() : Lundi Mardi Mercredi Jeudi Vendredi Samedi Dimanche
advance
Cette fonction est utilisée pour incrémenter la position de l'itérateur jusqu'au nombre spécifié mentionné dans ses arguments.
S'il s'agit d'un itérateur à accès aléatoire, la fonction n'utilise qu'une seule fois l'opérateur+ ou l'opérateur-. Sinon, la fonction utilise à plusieurs reprises l'opérateur d'augmentation ou de diminution (opérateur++ ou opérateur--) jusqu'à ce que n éléments aient été avancés.
Exemple 2
#include<string> #include<iterator> // classe itérateur #include<vector> // classe vecteur (conteneur) using namespace std; int main ( ){ // définir un vecteur vector<string> jrs = {"Lundi", "Mardi", "Mercredi","Jeudi", "Vendredi", "Samedi","Dimanche" }; vector<string>::iterator it; it=std::begin(jrs); // faire avancer l'itérateur de 3 pas std::advance(it, 3); cout << "La position de l'iterateur apres avoir avance est : "; cout << *it << " "; return 0; }
Résultat
La position de l'iterateur apres avoir avance est : Jeudi
next
Cette fonction renvoie un itérateur pointant sur l'élément qu'il pointerait s'il était avancé de n positions.
prev
Cette fonction renvoie un itérateur pointant sur l'élément qu'il pointerait s'il était avancé de -n positions.
Exemple 3
#include<iostream> #include<string> #include<iterator> // classe itérateur #include<vector> // classe vecteur (conteneur) using namespace std; int main ( ){ // définir un vecteur vector<string> jrs = {"Lundi", "Mardi", "Mercredi","Jeudi", "Vendredi", "Samedi","Dimanche" }; vector<string>::iterator it; it=std::begin(jrs); while(it < std::end(jrs)){ cout<< *it << '\t'; it=std::next(it); } cout<< '\n'; cout<< "ordre inverse : "<<endl; it=std::end(jrs); // pointer vers le dernier élément it=std::prev(it,1); while(it>std::begin(jrs)){ cout<< *it << '\t'; it=std::prev(it); } return 0; }
Résultat
Lundi Mardi Mercredi Jeudi Vendredi Samedi Dimanche ordre inverse : Dimanche Samedi Vendredi Jeudi Mercredi Mardi
Exemple 4
#include<iostream> #include<string> #include<iterator> // classe itérateur #include<vector> // classe vecteur (conteneur) using namespace std; int main ( ){ // définir un vecteur vector<string> jrs = {"Lundi", "Mardi", "Mercredi","Jeudi", "Vendredi", "Samedi","Dimanche" }; vector<string>::iterator it; it=std::begin(jrs); // ou simplmement it=jrs.begin(); cout<< "4eme element est : "<< *std::next(it,3); cout << '\n'; it=std::end(jrs);// ou simplmement it=jrs.end(); cout<< "Avant dernier element est : "<< *std::prev(it,2); return 0; }
Résultat
4eme element est : Jeudi Avant dernier element est : Samedi
S'il s'agit d'un itérateur à accès aléatoire, les fonctions prev et next n'utilisent qu'une seule fois l'opérateur+ ou l'opérateur-. Sinon, Elles utilisent à plusieurs reprises l'opérateur d'augmentation ou de diminution (opérateur++ ou opérateur--) sur l'itérateur copié jusqu'à ce que n éléments aient été avancés.
distance
Cette fonction renvoie la distance entre les itérateurs. S'il s'agit d'un itérateur à accès aléatoire, la fonction utilise l'opérateur- pour le calculer. Sinon, la fonction utilise l'opérateur d'augmentation (opérateur++) à plusieurs reprises.
Exemple 5
#include<iostream> #include<string> #include<iterator> // classe itérateur #include<vector> // classe vecteur (conteneur) using namespace std; int main ( ){ // définir un vecteur vector<string> jrs = {"Lundi", "Mardi", "Mercredi","Jeudi", "Vendredi", "Samedi","Dimanche" }; vector<string>::iterator debut=jrs.begin(); vector<string>::iterator fin=jrs.end(); cout<< "Distance entre le pointeur end et debut est : "<< std::distance(debut,fin); return 0; }
Résultat
Distance entre le pointeur end et debut est : 7
Itérateur à accès aléatoire
Exemple 6
#include<iostream> #include<string> #include<iterator> // classe itérateur #include<vector> // classe vecteur (conteneur) using namespace std; int main ( ){ // définir un vecteur vector<string> jrs = {"Lundi", "Mardi", "Mercredi","Jeudi", "Vendredi", "Samedi","Dimanche" }; vector<string>::iterator it=jrs.begin(); cout<< "déplacer l'iterateur de 3 pas : "<< * (it+3); cout<< '\n'; it=jrs.end(); cout<< "déplacer l'iterateur de 3 pas a partir de fin: "<< * (it-3); return 0; }
Résultat
deplacer l'iterateur de 3 pas : Jeudi deplacer l'iterateur de 3 pas a partir de fin: Vendredi