HOWTO · C++

Comment parcourir un vecteur en C++

Découvrez quatre façons de parcourir un vecteur en C++ : avec une boucle indexée, une boucle basée sur une plage, des itérateurs ou `std::for_each`.

Sur cette page

Pour parcourir simplement chaque élément d’un std::vector, utilisez une boucle for basée sur une plage. Choisissez une boucle indexée lorsque la position compte, des itérateurs lorsqu’un algorithme attend une plage d’itérateurs, ou std::for_each pour appliquer une fonction à chaque élément. Les exemples ci-dessous ciblent C++14.

Parcourir un vecteur avec une boucle for indexée

Une boucle indexée donne accès à la fois à l’élément et à sa position. Les trois clauses de son en-tête sont séparées par des points-virgules : initialiser l’indice, continuer tant qu’il est inférieur à size(), puis l’incrémenter. Cet exemple complet en C++14 illustre cette forme ; aucun résultat d’exécution n’est annoncé ici.

#include <cstddef>
#include <iostream>
#include <vector>

int main() {
    const std::vector<int> values = {45, 54, 87, 78};

    for (std::size_t i = 0; i < values.size(); ++i) {
        std::cout << values[i] << ' ';
    }
    std::cout << '\n';
}

Dans cet exemple, values est déclaré const et ne peut donc pas être modifié : utilisez values[i] pour consulter l’élément à un indice donné, mais pas pour le changer. Pour mettre à jour une position précise, déclarez le vecteur comme modifiable (par exemple, std::vector<int> values = {45, 54, 87, 78};) et affectez une valeur à values[i] dans la boucle. La condition i < values.size() maintient chaque indice parmi les positions valides du vecteur. L’accès par indice est utile lorsque la position d’un élément compte, par exemple pour associer des valeurs à celles d’une autre séquence ou modifier une case précise. Si vous devez seulement lire ou modifier chaque valeur à tour de rôle, une boucle basée sur une plage est généralement plus simple, car elle évite de gérer un indice.

size() renvoie le nombre d’éléments, tandis que l’indexation commence à zéro : si le vecteur n’est pas vide, le dernier élément se trouve donc à size() - 1. La condition stricte « inférieur à » empêche la boucle d’utiliser ce nombre comme indice. Lorsque vous adaptez la boucle à d’autres types d’éléments, veillez à ce que le type de l’indice soit compatible avec celui de la taille du vecteur.

Utiliser une boucle for basée sur une plage

Une boucle for basée sur une plage parcourt chaque élément sans gérer d’indice. Utilisez const auto& pour lire les éléments sans les copier, et auto& lorsque la boucle doit modifier les valeurs d’origine. Cet exemple en C++14 illustre les deux formes ; aucun résultat d’exécution n’est annoncé ici.

#include <iostream>
#include <vector>

int main() {
    std::vector<int> values = {45, 54, 87, 78};

    for (const auto& value : values) {
        std::cout << value << ' ';
    }
    std::cout << '\n';

    for (auto& value : values) {
        value += 1;
    }
}

La première boucle lie chaque value à une référence en lecture seule. La seconde utilise une référence modifiable : les affectations changent donc les éléments correspondants de values. Si vous avez seulement besoin de consulter les valeurs, préférez la forme const pour rendre cette intention explicite.

Parcourir un vecteur avec des itérateurs

Utilisez un itérateur lorsqu’une interface accepte une paire de positions ou lorsque vous devez avancer explicitement dans un conteneur. Commencez à begin() et poursuivez jusqu’à end(). L’itérateur end() désigne la position située juste après le dernier élément : déréférencez l’itérateur courant, jamais end() lui-même. Cet exemple en C++14 illustre le parcours ; aucun résultat d’exécution n’est annoncé ici.

#include <iostream>
#include <vector>

int main() {
    const std::vector<int> values = {45, 54, 87, 78};

    for (std::vector<int>::const_iterator it = values.begin();
         it != values.end(); ++it) {
        std::cout << *it << ' ';
    }
    std::cout << '\n';
}

La comparaison != exprime la plage d’itérateurs semi-ouverte habituelle [begin(), end()). Un const_iterator permet de lire chaque élément sans le modifier par l’intermédiaire de cet itérateur.

Cette même paire d’itérateurs peut être transmise aux algorithmes standard. Le parcours explicite avec des itérateurs est donc utile lorsque le code travaille déjà avec des plages d’itérateurs. Pour un vecteur en lecture seule, begin() et end() fournissent des itérateurs constants ; pour un vecteur modifiable, ils fournissent des itérateurs qui permettent de modifier les éléments lorsqu’on les déréférence.

Appliquer une opération avec std::for_each

std::for_each, défini dans <algorithm>, applique une fonction à chaque élément de la plage semi-ouverte allant de begin() jusqu’à end(), sans inclure ce dernier. Une lambda place l’opération près du parcours. Cet exemple en C++14 illustre l’ajout de dix à chaque valeur au moyen d’une référence modifiable ; aucun résultat d’exécution n’est annoncé ici.

#include <algorithm>
#include <iostream>
#include <vector>

int main() {
    std::vector<int> values = {1, 2, 3};

    std::for_each(values.begin(), values.end(), [](int& value) {
        value += 10;
    });

    for (const auto& value : values) {
        std::cout << value << ' ';
    }
    std::cout << '\n';
}

Utilisez un paramètre de lambda const int& lorsque la fonction ne fait que lire les éléments. Pour un parcours simple, une boucle basée sur une plage est généralement plus facile à lire ; choisissez std::for_each lorsque le fait de transmettre l’opération sous forme de fonction convient au code environnant. Les quatre méthodes parcourent les mêmes éléments du vecteur, mais diffèrent par l’accès aux positions et la manière d’appliquer les opérations.