Pourquoi un vector plutôt qu'un tableau brut
Un tableau brut a une taille fixe figée à la compilation et oublie sa longueur dès que tu le passes à une fonction. std::vector corrige les deux problèmes : c'est un tableau redimensionnable qui suit sa propre longueur, grandit à la demande et nettoie sa propre mémoire. En C++ moderne, vector est le conteneur par défaut - ne recours à un tableau brut que si tu as une raison précise de ne pas le faire.
Inclus <vector>, puis déclare-en un avec le type de l'élément entre chevrons :
scores.size() donne toujours la longueur actuelle - pas de int n séparé à maintenir synchronisé, ni d'astuces avec sizeof. Le {90, 75, 100, 60} est un initialiseur entre accolades ; le vector comprend tout seul qu'il lui faut quatre emplacements.
Créer et initialiser un vector
Il existe plusieurs façons d'en construire un, selon ce que tu sais d'avance :
Attention au piège parenthèses vs accolades : vector<int> tens(5, 10) crée cinq copies de 10, tandis que vector<int> tens{5, 10} crée un vector de deux éléments contenant 5 et 10. Les parenthèses signifient « taille et valeur de remplissage » ; les accolades signifient « ces éléments littéraux ».
Ajouter et retirer des éléments
Tout l'intérêt d'un vector, c'est qu'il grandit. push_back ajoute à la fin, et pop_back retire de la fin :
back() renvoie le dernier élément et front() le premier - plus propre que v[v.size() - 1] et v[0]. Depuis C++11, tu peux aussi utiliser emplace_back(args...) pour construire un élément sur place, ce qui évite une copie temporaire pour les types lourds.
Une erreur fréquente chez les débutants est d'appeler front() ou back() sur un vector vide. C'est un comportement indéfini, pas une erreur - protège-toi toujours d'abord avec if (!v.empty()).
Lire des éléments : [] vs at()
Tu indexes un vector exactement comme un tableau avec []. Mais [] ne fait aucune vérification de limites - un indice hors plage est un comportement indéfini, qui peut lire silencieusement des données invalides ou planter plus tard dans un endroit déroutant :
vector<int> v = {1, 2, 3};
cout << v[10]; // COMPORTEMENT INDÉFINI - aucune vérification, aucune erreur
Quand tu veux de la sûreté, utilise at(). Il vérifie l'indice et lève std::out_of_range en cas d'accès incorrect, donc tu obtiens un échec clair plutôt qu'une corruption :
Règle générale : utilise [] dans les boucles serrées où tu as déjà prouvé que l'indice est valide, et at() aux frontières où une entrée incorrecte pourrait se glisser.
Parcourir un vector
La façon la plus propre de parcourir un vector est la boucle for basée sur une plage. Prends les éléments par const auto& pour lire sans copier, ou par auto& pour les modifier sur place :
Si tu as réellement besoin de l'indice (pour comparer des voisins, par exemple), utilise une boucle de comptage classique - mais note que size() renvoie un type non signé (size_t). Comparer un int i signé à cette valeur peut déclencher des avertissements du compilateur et des dépassements surprenants ; préfère donc size_t i ou une boucle basée sur une plage quand tu le peux :
for (size_t i = 0; i < v.size(); i++) { // size_t, pas int
cout << v[i];
}
size, capacity et reserve
Un vector garde deux nombres : size() (combien d'éléments il contient) et capacity() (combien il peut contenir avant de devoir grandir). Quand un push_back dépasse la capacité, le vector alloue un bloc plus grand, copie chaque élément et libère l'ancien bloc. C'est pour cela que des push_back répétés sont peu coûteux en amorti, mais que chaque réallocation individuelle n'est pas gratuite :
Si tu sais à peu près combien d'éléments tu vas ajouter, appelle d'abord reserve() pour sauter les réallocations répétées. Note que reserve() change la capacité, pas la taille - le vector a toujours zéro élément tant que tu n'en as pas inséré.
Cette réallocation est aussi à l'origine du bug le plus vicieux des vectors. Comme grandir déplace le stockage, tout pointeur, référence ou itérateur que tu as sauvegardé dans le vector devient pendouillant après un push_back qui réalloue :
vector<int> v = {1, 2, 3};
int& first = v[0]; // référence dans le vector
v.push_back(4); // peut réallouer...
cout << first; // PENDOUILLANT - peut pointer vers de la mémoire libérée
Cela vaut aussi pour les itérateurs : ne fais pas de push_back ni d'erase pendant que tu itères avec un itérateur sauvegardé. Si tu dois retirer des éléments en bouclant, utilise la valeur de retour d'erase, ou l'idiome erase-remove avec std::remove.
Suivant : map
Un vector est parfait quand tu cherches les choses par position - élément 0, élément 1, et ainsi de suite. Mais souvent, tu veux plutôt chercher les choses par une clé : un nom d'utilisateur, un identifiant de produit, un mot. C'est à cela que sert std::map. Ensuite, nous aborderons map, le conteneur clé-valeur du C++, y compris comment insérer, rechercher et parcourir des entrées - et le piège du [] qui crée une valeur par défaut, qui surprend presque tout le monde.
Questions fréquentes
Qu'est-ce qu'un vector en C++ ?
Un std::vector est un tableau dynamique (redimensionnable) de la bibliothèque standard du C++. Contrairement à un tableau brut, il connaît sa propre taille, grandit automatiquement quand tu ajoutes des éléments avec push_back, et libère sa mémoire pour toi. Inclus <vector> et écris vector<int> v; pour en créer un.
Quelle est la différence entre [] et at() sur un vector en C++ ?
v[i] ne fait aucune vérification de limites - un indice hors plage est un comportement indéfini (plantage ou corruption silencieuse). v.at(i) vérifie l'indice et lève std::out_of_range s'il est invalide. Utilise [] dans les boucles critiques où tu as déjà validé l'indice, et at() quand tu veux un échec sûr et facile à déboguer.
push_back invalide-t-il les pointeurs et les références dans un vector C++ ?
Oui, potentiellement. Quand un vector n'a plus de capacité, push_back réalloue son stockage vers un nouveau bloc, ce qui invalide tous les pointeurs, références et itérateurs vers les anciens éléments. Ne conserve pas une référence à un élément à travers un push_back, et appelle reserve() à l'avance si tu peux pour éviter les réallocations surprises.