Soit v1 le vecteur cible, v2 doit être ajouté à l'arrière de celui-ci.
Je fais maintenant:
v1.reserve(v1.size() + v2.size());
copy(v2.begin(), v2.end(), back_inserter(v1));
Est-ce le moyen le plus efficace? Ou cela peut-il être fait simplement en copiant un morceau de mémoire? Merci!
Après beaucoup de discussions (et un commentaire raisonnable de Matthieu M. et villintehaspam), je changerai ma suggestion en
v1.insert( v1.end(), v2.begin(), v2.end() );
Je vais garder l'ancienne suggestion ici:
v1.reserve( v1.size() + v2.size() );
v1.insert( v1.end(), v2.begin(), v2.end() );
Il y a quelques raisons de le faire de cette dernière manière, bien qu'aucune ne soit suffisamment solide:
reserve
, mais pour une implémentation spécifique, cela pourrait être vrai. Si vous cherchez un goulot d'étranglement, il pourrait être difficile de vérifier cela.reserve
nous avons une garantie C++ Standard qu'il n'y aura qu'une seule réallocation, tandis que insert
peut être implémenté de manière inefficace et faire plusieurs réallocations (également quelque chose à tester avec une implémentation particulière).Probablement mieux et plus simple d'utiliser une méthode dédiée: vector.insert
v1.insert(v1.end(), v2.begin(), v2.end());
Comme Michael le mentionne, à moins que les itérateurs ne soient des itérateurs d'entrée, le vecteur déterminera la taille requise et copiera les données ajoutées en une seule fois avec une complexité linéaire.
J'ai simplement fait une mesure rapide des performances avec le code suivant et
v1.insert( v1.end(), v2.begin(), v2.end() );
semble être le bon choix (comme déjà indiqué ci-dessus). Néanmoins, vous trouverez les performances signalées ci-dessous.
Code de test:
#include <vector>
#include <string>
#include <boost/timer/timer.hpp>
//==============================================================================
//
//==============================================================================
/// Returns a vector containing the sequence [ 0, ... , n-1 ].
inline std::vector<int> _range(const int n)
{
std::vector<int> tmp(n);
for(int i=0; i<n; i++)
tmp[i] = i;
return tmp;
}
void test_perf_vector_append()
{
const vector<int> testdata1 = _range(100000000);
const vector<int> testdata2 = _range(100000000);
vector<int> testdata;
printf("--------------------------------------------------------------\n");
printf(" METHOD: Push_back()\n");
printf("--------------------------------------------------------------\n");
testdata.clear();
{ vector<int>().swap(testdata); }
testdata = testdata1;
{
boost::timer::auto_cpu_timer t;
for(size_t i=0; i<testdata2.size(); i++)
{
testdata.Push_back(testdata2[i]);
}
}
printf("--------------------------------------------------------------\n");
printf(" METHOD: reserve() + Push_back()\n");
printf("--------------------------------------------------------------\n");
testdata.clear();
{ vector<int>().swap(testdata); }
testdata = testdata1;
{
boost::timer::auto_cpu_timer t;
testdata.reserve(testdata.size() + testdata2.size());
for(size_t i=0; i<testdata2.size(); i++)
{
testdata.Push_back(testdata2[i]);
}
}
printf("--------------------------------------------------------------\n");
printf(" METHOD: insert()\n");
printf("--------------------------------------------------------------\n");
testdata.clear();
{ vector<int>().swap(testdata); }
testdata = testdata1;
{
boost::timer::auto_cpu_timer t;
testdata.insert( testdata.end(), testdata2.begin(), testdata2.end() );
}
printf("--------------------------------------------------------------\n");
printf(" METHOD: reserve() + insert()\n");
printf("--------------------------------------------------------------\n");
testdata.clear();
{ vector<int>().swap(testdata); }
testdata = testdata1;
{
boost::timer::auto_cpu_timer t;
testdata.reserve( testdata.size() + testdata.size() );
testdata.insert( testdata.end(), testdata2.begin(), testdata2.end() );
}
printf("--------------------------------------------------------------\n");
printf(" METHOD: copy() + back_inserter()\n");
printf("--------------------------------------------------------------\n");
testdata.clear();
{ vector<int>().swap(testdata); }
testdata = testdata1;
{
boost::timer::auto_cpu_timer t;
testdata.reserve(testdata.size() + testdata2.size());
copy(testdata2.begin(), testdata2.end(), back_inserter(testdata));
}
printf("--------------------------------------------------------------\n");
printf(" METHOD: reserve() + copy() + back_inserter()\n");
printf("--------------------------------------------------------------\n");
testdata.clear();
{ vector<int>().swap(testdata); }
testdata = testdata1;
{
boost::timer::auto_cpu_timer t;
testdata.reserve(testdata.size() + testdata2.size());
copy(testdata2.begin(), testdata2.end(), back_inserter(testdata));
}
}
Avec Visual Studio 2008 SP1, x64, mode Release,/O2/LTCG, la sortie est la suivante:
--------------------------------------------------------------
METHOD: Push_back()
--------------------------------------------------------------
0.933077s wall, 0.577204s user + 0.343202s system = 0.920406s CPU (98.6%)
--------------------------------------------------------------
METHOD: reserve() + Push_back()
--------------------------------------------------------------
0.612753s wall, 0.452403s user + 0.171601s system = 0.624004s CPU (101.8%)
--------------------------------------------------------------
METHOD: insert()
--------------------------------------------------------------
0.424065s wall, 0.280802s user + 0.140401s system = 0.421203s CPU (99.3%)
--------------------------------------------------------------
METHOD: reserve() + insert()
--------------------------------------------------------------
0.637081s wall, 0.421203s user + 0.218401s system = 0.639604s CPU (100.4%)
--------------------------------------------------------------
METHOD: copy() + back_inserter()
--------------------------------------------------------------
0.743658s wall, 0.639604s user + 0.109201s system = 0.748805s CPU (100.7%)
--------------------------------------------------------------
METHOD: reserve() + copy() + back_inserter()
--------------------------------------------------------------
0.748560s wall, 0.624004s user + 0.124801s system = 0.748805s CPU (100.0%)
Si vous utilisez Boost, vous pouvez télécharger la version de développement de la bibliothèque RangeEx depuis le coffre-fort Boost . Cette lib. a été accepté dans Boost il y a quelque temps, mais jusqu'à présent, il n'a pas été intégré à la distribution principale. Vous y trouverez un nouvel algorithme basé sur une plage qui fait exactement ce que vous voulez:
boost::Push_back(v1, v2);
En interne, cela fonctionne comme la réponse donnée par UncleBens, mais le code est plus concis et lisible.
Si vous avez un vecteur de pod-types et que vous avez vraiment besoin de performances, vous pouvez utiliser memcpy, qui devrait être plus rapide que vector <>. Insert (...):
v2.resize(v1.size() + v2.size());
memcpy((void*)&v1.front(), (void*)&v2[v1.size()], sizeof(v1.front())*v1.size());
Mise à jour: Bien que je n'utilise cela que si les performances sont vraiment, vraiment, nécessaires, le code is est sûr pour les types de pod.