HOWTO · C++

Copier un objet conteneur vectoriel en C++

Cet article montre comment copier un objet conteneur vectoriel en C++.

Sur cette page

Pour copier un std::vector en C++, utilisez son constructeur de copie pour créer un nouveau vecteur et l’affectation par copie pour remplacer le contenu d’un vecteur existant. Pour une plage donnée, utilisez le constructeur prenant une plage. std::copy convient lorsque la plage de destination dispose déjà de suffisamment d’espace, tandis que std::back_inserter ajoute les éléments à la destination. Ces opérations copient les éléments selon leur type ; elles ne copient pas récursivement les objets accessibles par des pointeurs.

Copier un vecteur avec son constructeur de copie ou son opérateur d’affectation

L’initialisation par copie construit un nouveau vecteur à partir d’un vecteur existant : std::vector<int> copy = source;. L’initialisation directe fait de même avec des parenthèses : std::vector<int> copy(source);. Si la destination existe déjà, utilisez l’affectation : destination = source;. L’affectation remplace les éléments de la destination. Incluez <vector> pour ces formes.

Exécutez cet exemple :

Le code et les libellés ou sorties affichés dans cette section restent en anglais.

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

int main() {
    const std::vector<int> source{2, 4, 6};
    std::vector<int> copy = source;
    std::vector<int> destination{9};
    destination = source;

    for (std::size_t i = 0; i < copy.size(); ++i) {
        if (i != 0) {
            std::cout << ' ';
        }
        std::cout << copy[i];
    }
    std::cout << '\n';
    for (std::size_t i = 0; i < destination.size(); ++i) {
        if (i != 0) {
            std::cout << ' ';
        }
        std::cout << destination[i];
    }
    std::cout << '\n';
}
2 4 6
2 4 6

Ce programme affiche chaque vecteur copié sur sa propre ligne. Les éléments de son std::vector<int> sont des valeurs : modifier un entier dans un vecteur ne modifie donc pas l’entier correspondant dans l’autre.

Copier une plage avec le constructeur de plage de vector

Le constructeur de plage prend une plage d’itérateurs semi-ouverte : le premier itérateur est inclus et le second est exclu. Utilisez des parenthèses pour distinguer ce constructeur de la syntaxe des listes d’initialisation.

std::vector<int> copy(source.begin(), source.end()); crée une copie de toute la plage. Pour une sous-plage, utilisez std::vector<int> middle(source.begin() + 1, source.end() - 1); lorsque ces itérateurs désignent les éléments souhaités.

La première déclaration copie tous les éléments ; dans cet exemple, la seconde copie la plage intérieure. Les deux itérateurs doivent désigner une plage valide dans le même vecteur source. Cette méthode est pratique lorsqu’il faut créer une nouvelle destination pour copier un vecteur entier ou une sous-plage.

Copier une plage avec std::copy

std::copy écrit dans une plage de destination existante. Incluez <algorithm> et vérifiez que la destination contient au moins autant d’éléments que la plage source avant la copie. L’algorithme n’agrandit pas lui-même un vecteur.

std::vector<int> destination(source.size());, suivi de std::copy(source.begin(), source.end(), destination.begin());, fournit une plage de destination assez grande pour la source.

Pour une sous-plage, transmettez ses itérateurs de début et de fin et prévoyez suffisamment d’éléments dans la destination. Les plages source et destination ne doivent pas se chevaucher d’une manière qui enfreint les exigences de l’algorithme.

Ajouter les éléments copiés avec std::back_inserter

Pour ajouter des éléments et laisser le vecteur grandir au besoin, incluez <algorithm> et <iterator>, puis utilisez std::back_inserter :

Par exemple, std::vector<int> destination{10};, suivi de std::copy(source.begin(), source.end(), std::back_inserter(destination));, ajoute les éléments de la source.

La valeur 10 d’origine reste au début, suivie des valeurs de la source. Cette forme est utile lorsque la destination contient déjà des éléments ou que sa taille finale n’est pas définie à l’avance.

Copier les éléments avec une boucle et push_back

Une boucle rend explicite l’opération effectuée sur chaque élément. push_back ajoute chaque valeur copiée à la fin ; une destination existante est donc prolongée.

Une boucle directe s’écrit ainsi après la déclaration de std::vector<int> destination; : for (const int& value : source) { destination.push_back(value); }.

Pour une copie ordinaire, le constructeur de copie du vecteur ou son constructeur de plage est généralement plus clair. Une boucle convient lorsque chaque élément doit être transformé ou filtré au moment de son ajout. Comme les opérations standard sur les vecteurs, la boucle copie chaque élément selon son type.

Remplacer ou insérer des éléments dans la destination avec assign et insert

Utilisez assign(first, last) pour remplacer la destination par une plage. Utilisez insert(position, first, last) pour insérer la plage source à une position donnée tout en conservant les autres éléments de la destination.

Utilisez destination.assign(source.begin(), source.end()); pour remplacer son contenu. Utilisez destination.insert(destination.begin(), source.begin(), source.end()); pour insérer la plage source au début.

La position d’insertion doit être un itérateur valide dans la destination. Si l’insertion entraîne une réallocation du stockage du vecteur, tous les itérateurs, pointeurs et références vers ses éléments sont invalidés. Sans réallocation, les itérateurs et références situés au point d’insertion ou après celui-ci sont tout de même invalidés ; ceux qui le précèdent restent valides. Récupérez à nouveau les itérateurs et références concernés après l’insertion.

Comprendre ce que copie un vecteur

Un std::vector stocke ses éléments de façon contiguë et gère lui-même leur stockage. Copier un vecteur crée un vecteur distinct contenant des copies de ses éléments. Pour un std::vector<int>, les valeurs entières sont copiées : affecter ensuite une nouvelle valeur à un élément de l’un des vecteurs ne modifie pas la valeur de l’autre.

Pour les autres types d’éléments, le comportement dépend de leur opération de copie. Par exemple, copier un vecteur de pointeurs bruts copie les valeurs des pointeurs ; cela ne crée pas de nouveaux objets pointés. Si les éléments sont des pointeurs intelligents, la copie suit leur sémantique propre, comme le partage de propriété avec std::shared_ptr. Un vecteur distinct n’implique donc pas toujours que les objets accessibles par ses éléments soient indépendants.

Choisir une méthode pour copier un vecteur

Choisissez la construction par copie ou le constructeur de plage pour créer un nouveau vecteur. Choisissez l’affectation par copie ou assign pour remplacer une destination existante. Utilisez insert pour insérer une plage à une position donnée, et std::copy avec std::back_inserter pour ajouter des éléments tout en agrandissant la destination. Utilisez std::copy avec une destination dimensionnée lorsque vous voulez écrire dans une plage d’éléments déjà allouée. Une boucle avec push_back est utile si la copie nécessite aussi un traitement personnalisé de chaque élément.

Pour copier un vecteur entier dans un nouveau vecteur, privilégiez le constructeur de copie ; utilisez un constructeur de plage pour sélectionner certains éléments. Pour un vecteur existant, choisissez l’affectation ou assign pour remplacer son contenu, insert pour insérer des éléments à une position donnée, ou std::back_inserter pour les ajouter à la fin.