web-dev-qa-db-fra.com

Meilleure façon d'ajouter un vecteur à un vecteur

std::vector<int> a;
std::vector<int> b;
std::vector<int> c;

Je voudrais concaténer ces trois vecteurs en ajoutant les éléments de b et c à a. Quelle est la meilleure façon de procéder et pourquoi?


1) En utilisant vector::insert:

a.reserve(a.size() + b.size() + c.size());
a.insert(a.end(), b.begin(), b.end());
a.insert(a.end(), c.begin(), c.end());
b.clear();
c.clear();

2) En utilisant std::copy:

a.reserve(a.size() + b.size() + c.size());
std::copy(b.begin(), b.end(), std::inserter(a, a.end()));
std::copy(c.begin(), c.end(), std::inserter(a, a.end()));
b.clear();
c.clear();

) En utilisant std::move (de C++11):

a.reserve(a.size() + b.size() + c.size());
std::move(b.begin(), b.end(), std::inserter(a, a.end()));
std::move(c.begin(), c.end(), std::inserter(a, a.end()));
b.clear();
c.clear();
43
vdenotaris

À mon avis, votre première solution est la meilleure solution.

vector<>::insert est conçu pour ajouter un élément, c'est donc la solution la plus adéquate.

Vous pouvez appeler reserve sur le vecteur de destination pour réserver de l'espace, mais à moins que vous n'ajoutiez beaucoup de vecteur ensemble, il est probable qu'il ne fournira pas beaucoup d'avantages: vector<>::insert sachez combien d'éléments seront ajoutés, vous éviterez un seul appel reserve.

Remarque: si ceux-ci étaient vector de type plus complexe (c'est-à-dire une classe personnalisée, ou même std::string), puis en utilisant std::move pourrait vous fournir une amélioration des performances, car cela éviterait le constructeur de copie. Cependant, pour un vecteur de int, cela ne vous procurera aucun avantage.

Note 2: Il convient de mentionner que l'utilisation de std::move rendra le contenu de votre source vector inutilisable.

24
Xaqq

En supposant que vous vouliez copier et ne pas déplacer, ce serait la meilleure façon:

a.reserve(a.size()+b.size()+c.size()); // Reserve space first
a.insert(a.end(),b.begin(),b.end());
a.insert(a.end(),c.begin(),c.end());

Si vous souhaitez déménager:

a.reserve(a.size()+b.size()+c.size()); // Reserve space first
a.insert(a.end(),std::make_move_iterator(b.begin()),
         std::make_move_iterator(b.end()));
a.insert(a.end(),std::make_move_iterator(c.begin()),
         std::make_move_iterator(c.end()));
b.swap(std::vector<int>()); // Clear and deallocate space
c.swap(std::vector<int>()); // Clear and deallocate space

Mise à jour: Vous avez modifié plusieurs fois votre question, ce qui en fait une sorte de cible mobile. Votre première option est maintenant très similaire à ma première suggestion.

mise à jour 2: à partir de C++ 11, vous n'aurez peut-être plus à utiliser l'astuce "swap with empty vector" pour effacer et désallouer l'espace, en fonction de l'implémentation de votre bibliothèque de vector. Les éléments suivants peuvent faire le travail d'une manière plus intuitive:

// Empty the vectors of objects
b.clear(); 
c.clear();

// Deallocate the memory allocated by the vectors 
// Note: Unlike the swap trick, this is non-binding and any space reduction
//       depends on the implementation of std::vector
b.shrink_to_fit();
c.shrink_to_fit();
19
Michael Goldshteyn

Le premier est le meilleur choix car insert peut déterminer le nombre d'éléments qu'il ajoute et redimensionner le vecteur pour qu'il s'adapte avant de commencer la copie. Les autres n'ont pas ces informations, donc pourraient finir par redimensionner après une copie, ce qui serait plus lent que le redimensionnement au début, ou redimensionner plus d'une fois.

Cependant, comme l'indique @michaelgoldshteyn, puisque vous allez faire deux insertions, vous pouvez également redimensionner le tableau vous-même avec la taille finale, ce qui peut éventuellement enregistrer un redimensionnement.

1
Pete Becker

Si vous voulez vraiment ajouter les données de b et c dans le vecteur a, vous devez faire une insertion (qui est en fait votre 1. ):

a.reserve( a.size() + b.size() + c.size() ); // preallocate memory (see why)
a.insert( a.end(), b.begin(), b.end() );
a.insert( a.end(), c.begin(), c.end() );

Selon le compilateur std::copy (votre 2.) devrait normalement être aussi rapide.

Depuis un std::vector doit toujours être contigu en mémoire, vous ne pouvez pas simplement déplacer (comme défini en C++ 11) et si vous connaissez la taille finale vous devez réserver votre vecteur (cela évitera les réallocations inutiles de votre vecteur). Mais si vous vous souciez vraiment des performances, laissez-les trois std::vector et parcourez-les lorsque vous devez lire leurs données.

0
Kyle_the_hacker