moyen rapide de copier un vecteur dans un autre

155

Je préfère deux manières:

void copyVecFast(const vec<int>& original)
{
  vector<int> newVec;
  newVec.reserve(original.size());
  copy(original.begin(),original.end(),back_inserter(newVec));
}

void copyVecFast(vec<int>& original)
{

  vector<int> newVec;
  newVec.swap(original); 
}

Comment faites-vous?

gsamaras
la source
14
Le deuxième a un nom trompeur - car ce n'est pas une copie (bien que ce soit rapide).
Anonyme

Réponses:

125

Votre deuxième exemple ne fonctionne pas si vous envoyez l'argument par référence. Vouliez-vous dire

void copyVecFast(vec<int> original) // no reference
{

  vector<int> new_;
  new_.swap(original); 
}

Cela fonctionnerait, mais un moyen plus simple est

vector<int> new_(original);
rlbond
la source
Bon, ça marche. Mais cela ne fonctionne pas pour un tableau de vecteurs: par exemple: vector <int> A [n];
ABcDexter
8
C'est un échange, pas une copie.
sdd
1
@sdd - non, ce n'est pas le cas. Vérifiez la liste des arguments. originalest une copie de l'argument de la fonction.
rlbond
@rlbond a accidentellement voté contre la réponse :(, Pouvez-vous s'il vous plaît modifier le message, afin que je puisse supprimer le vote défavorable et donner le vote favorable?
Shubham Sharma il y a
250

Ce ne sont pas les mêmes, n'est-ce pas? L'un est une copie, l'autre est un échange . D'où les noms des fonctions.

Mon préféré est:

a = b;

aet bsont des vecteurs.

Daniel Earwicker
la source
3
En fait, l'approche passe par valeur, le compilateur appelle le constructeur de copie, puis permute cet élément nouvellement créé. C'est pourquoi rlbond suggère d'appeler directement le constructeur de copie pour obtenir le même effet.
David Rodríguez - dribeas
1
Cependant, vous ne pouvez pas appeler rlbon sans une fonction qui transmet l'original comme val. Sinon, l'original sera vide. La deuxième solution garantit que vous appellerez toujours par valeur et que vous ne perdrez donc pas la date dans le vecteur d'origine. (En supposant que les accords d'échange avec des pointeurs)
Eyad Ebrahim
Cela ne va-t-il pas déplacer les éléments de b vers a (laissant b avec une taille == 0)?
Jonathan.
1
@Jonathan. En supposant que vous parlez a = balors non. L'affectation signifie: rendre aégal bsans changer b. En revanche, std::swap(a, b)échangerait leur contenu (si bl ' sizeseraient maintenant ce qui aest avait été auparavant). Vous pensez peut-être à une opération de déplacement (comme cela se produit dans C ++ 11, mais pas dans une affectation ordinaire comme celle-ci). Un tel mouvement laisserait bdans un état, euh, "intéressant" - voir stackoverflow.com/questions/17730689/...
Daniel Earwicker
1
@Jonathan. Notez la double esperluette &&. Cette version ne sera utilisée que pour une référence rvalue. Il ne correspondra à aucune valeur non constante (comme bdans mon exemple ci-dessus). Vous pouvez ben créer un en disant a = std::move(b);Voir en.cppreference.com/w/cpp/language/value_category pour des niveaux de complexité encore plus élevés.
Daniel Earwicker
74

C'est un autre moyen valable de faire une copie d'un vecteur, utilisez simplement son constructeur:

std::vector<int> newvector(oldvector);

C'est encore plus simple que d'utiliser std::copypour parcourir le vecteur entier du début à la fin vers std::back_insertle nouveau vecteur.

Cela étant dit, le vôtre .swap()n'est pas une copie, il échange les deux vecteurs. Vous modifieriez l'original pour ne plus rien contenir! Ce qui n'est pas une copie.

X-Istence
la source
Plus flexible pour moi, c'est a = b;parce que j'ai déjà un champ membre aet qu'il me suffit de l'attribuer avec la nouvelle valeur deb
truthadjustr
20

Réponse directe:

  • Utilisez un =opérateur

Nous pouvons utiliser la fonction membre public std::vector::operator=du conteneur std::vectorpour assigner des valeurs d'un vecteur à un autre.

  • Utiliser une fonction constructeur

En outre, une fonction constructeur a également du sens. Une fonction constructeur avec un autre vecteur comme paramètre (par exemple x) construit un conteneur avec une copie de chacun des éléments dans x, dans le même ordre.

Mise en garde:

  • Ne pas utiliser std::vector::swap

std::vector::swapne copie pas un vecteur dans un autre, il échange en fait des éléments de deux vecteurs, comme son nom l'indique. En d'autres termes, le vecteur source à partir std::vector::swapduquel copier est modifié après avoir été appelé, ce qui n'est probablement pas ce à quoi vous vous attendez.

  • Copie profonde ou superficielle?

Si les éléments du vecteur source sont des pointeurs vers d'autres données, une copie complète est parfois souhaitée.

Selon wikipedia:

Une copie complète, ce qui signifie que les champs sont déréférencés: plutôt que des références aux objets en cours de copie, de nouveaux objets de copie sont créés pour tous les objets référencés et des références à ceux-ci sont placées dans B.

En fait, il n'existe actuellement aucun moyen intégré en C ++ de faire une copie complète. Tous les moyens mentionnés ci-dessus sont peu profonds. Si une copie complète est nécessaire, vous pouvez parcourir un vecteur et faire une copie des références manuellement. Alternativement, un itérateur peut être envisagé pour le parcours. La discussion sur l'itérateur va au-delà de cette question.

Références

La page de std::vectorsur cplusplus.com

Jerry Yang
la source
14

vous ne devez pas utiliser swap pour copier des vecteurs, cela changerait le vecteur "original".

passez plutôt l'original comme paramètre au nouveau.

Raz
la source
14
new_vector.assign(old_vector.begin(),old_vector.end()); // Method 1
new_vector = old_vector; // Method 2
FaridLU
la source
-14

Dans le cas où le vecteur existait DÉJÀ et que vous vouliez simplement copier, vous pouvez faire ceci:

newVec.resize(oldVec.size());
memcpy(&newVec.at(0), &oldVec.at(0), oldVec.size());
sgowd
la source
1
S'il vous plaît ne pas memcpy. De plus, cela ne fonctionnera pas car memcpy prend la taille en octets. De plus, si l'autre vecteur existe déjà, vous pouvez simplement faire newVec = oldVecce qui est identique à l'une des autres réponses.
FDinoff le
Oui, tu as raison. Je n'ai pas vu ça. @FDinoff, bien que ci-dessous un fonctionne, pourquoi suggérez-vous de ne pas utiliser memcpy? Cela semble être beaucoup plus rapide que newVec = oldVec. memcpy (& newVec.at (0), & oldVec.at (0), oldVec.size () * sizeof (int));
sgowd
1
Dans le cas général, copier un objet sans appeler son constructeur de copie peut conduire à des bogues subtils. Dans ce cas, j'aurais pensé qu'ils auraient eu la même performance. Si ce n'était pas le cas, je dirais que le vecteur n'a pas été optimisé pour les performances, car il devrait déjà le faire. Avez-vous réellement écrit un benchmark?
FDinoff
Je ne vous critiquais pas. Mon chef d'équipe a également suggéré la même chose et j'essayais de comprendre.
sgowd
(Je ne pensais pas que vous me critiquiez.) Y a-t-il encore quelque chose que vous ne comprenez pas?
FDinoff