Fondamentaux et Initialisation
Le conteneur std::vector fait partie intégrante de la STL en C++. Il s'agit d'un tableau dynamique capable de stocker des éléments de n'importe quel type. Pour l'utiliser, l'inclsuion de l'en-tête dédié est requise :
#include <vector>
Constructeurs et Méthodes d'Initialisation
La création d'un vecteur peut se faire de plusieurs manières selon les besoins :
std::vector<T> default_vec; // Constructeur par défaut
std::vector<T> range_vec(src.begin(), src.end()); // Copie à partir d'une plage d'itérateurs
std::vector<T> fill_vec(count, value); // Remplissage avec 'count' copies de 'value'
std::vector<T> copy_vec(original_vec); // Constructeur par copie
Exemples pratiques de déclaration :
std::vector<int> seq_numeric(15); // 15 entiers initialisés par défaut
std::vector<int> seq_zeroed(15, 0); // 15 entiers valant 0
std::vector<int> cloned(seq_numeric); // Copie intégrale
std::vector<int> partial(seq_zeroed.begin(), seq_zeroed.begin() + 5); // 5 premiers éléments
std::set<std::string> unique_names;
std::vector<std::string> names_vec(unique_names.begin(), unique_names.end());
int raw_data[] = {10, 20, 30};
std::vector<int> data_from_arr(raw_data, raw_data + 3);
std::vector<int> literal_vec{10, 20, 30}; // Initialisation par liste
Opérations Courantes sur les Vecteurs
Assignation
std::vector<int> primary = {5, 10, 15};
std::vector<int> secondary = primary; // Surcharge de l'opérateur =
std::vector<int> tertiary;
tertiary.assign(primary.begin(), primary.end()); // Assignation par plage
tertiary.assign(4, 99); // Assignation par remplissage (quatre 99)
Insertion d'Éléments
std::vector<int> buffer;
buffer.push_back(42); // Ajout en fin de séquence
buffer.insert(buffer.begin(), 100); // Insertion en première position
buffer.insert(buffer.begin() + 1, 3, 7); // Insertion de trois '7' à l'index 1
Suppression d'Éléments
std::vector<int> data = {1, 2, 3, 4, 5, 6};
data.pop_back(); // Retire le dernier élément
data.erase(data.begin() + 1); // Retire l'élément à l'index 1
data.erase(data.begin(), data.begin() + 2); // Retire une plage d'éléments
Accès aux Données
std::vector<int> metrics = {10, 20, 30, 40, 50};
int val1 = metrics.at(2); // Accès avec vérification des bornes
int val2 = metrics[3]; // Accès direct sans vérification
int first = metrics.front(); // Premier élément
int last = metrics.back(); // Dernier élément
Gestion de la Taille et de la Capacité
bool is_empty = metrics.empty(); // Vérifie si le conteneur est vide
size_t current_size = metrics.size(); // Nombre d'éléments actuels
size_t allocated_cap = metrics.capacity(); // Capacité totale allouée
metrics.resize(8); // Ajuste la taille (remplit avec 0 si agrandi)
metrics.resize(10, 99); // Ajuste la taille (remplit avec 99 si agrandi)
Permutation de Conteneurs
std::vector<int> alpha = {1, 2};
std::vector<int> beta = {3, 4, 5};
alpha.swap(beta); // Échange les pointeurs internes en O(1)
Structurse Multidimensionnelles
Pour créer une matrice ou un tableau 2D, l'initialisation nécessite de spécifier les dimensions :
int rows = 5;
int cols = 4;
// Méthode 1 : Initialisation via constructeur
std::vector<std::vector<int>> matrix_2d(rows, std::vector<int>(cols, 0));
// Méthode 2 : Initialisation par défaut
std::vector<std::vector<int>> grid(rows, std::vector<int>(cols));
// Méthode 3 : Redimensionnement dynamique
std::vector<std::vector<int>> dynamic_grid;
dynamic_grid.resize(rows);
for (int r = 0; r < rows; ++r) {
dynamic_grid[r].resize(cols);
}
Idiomes Avancés et Pièges Fréquents
Retourner un Vecteur Directement
Il est possible de retourner un vecteur en utilisant une liste d'initialisation directement dans l'instruction return :
#include <vector>
class ArraySolver {
public:
std::vector<int> findPairIndices(const std::vector<int>& sorted_arr, int goal) {
int left_ptr = 0;
int right_ptr = static_cast<int>(sorted_arr.size()) - 1;
while (left_ptr < right_ptr) {
int current_sum = sorted_arr[left_ptr] + sorted_arr[right_ptr];
if (current_sum == goal) {
return {left_ptr + 1, right_ptr + 1}; // Retour direct
} else if (current_sum < goal) {
++left_ptr;
} else {
--right_ptr;
}
}
return {};
}
};
Piège d'Initialisation : Parenthèses vs Accolades
La syntaxe utilisée pour l'initialisation change radicalement le comportement :
int count = 5;
int value = 8;
// Crée un vecteur de 5 éléments, tous initialisés à 8
std::vector<int> filled_vec(count, value);
// Crée un vecteur de 2 éléments contenant les valeurs 5 et 8
std::vector<int> literal_vec{count, value};
Piège d'Accès par Index sur un Vecteur Vide
Il est impossible d'utiliser l'opérateur [] pour assigner une valeur à un index qui n'existe pas encore. Le vecteur doit d'abord être dimensionné ou utiliser push_back :
std::vector<int> empty_vec;
// empty_vec[0] = 10; // Comportement indéfini / Segfault
// Approche correcte 1 : Ajout dynamique
empty_vec.push_back(10);
// Approche correcte 2 : Redimensionnement préalable
empty_vec.resize(1);
empty_vec[0] = 10;