Je pensais que emplace_back
serait le gagnant, en faisant quelque chose comme ça:
v.Push_back(myClass(arg1, arg2));
car emplace_back
construirait l'objet immédiatement dans le vecteur, tandis que Push_back
, construirait d'abord un objet anonyme puis le copierait dans le vecteur. Pour plus voir this question.
Google donne également this et this questions.
J'ai décidé de les comparer pour un vecteur qui serait rempli d'entiers.
Voici le code de l'expérience:
#include <iostream>
#include <vector>
#include <ctime>
#include <ratio>
#include <chrono>
using namespace std;
using namespace std::chrono;
int main() {
vector<int> v1;
const size_t N = 100000000;
high_resolution_clock::time_point t1 = high_resolution_clock::now();
for(size_t i = 0; i < N; ++i)
v1.Push_back(i);
high_resolution_clock::time_point t2 = high_resolution_clock::now();
duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
std::cout << "Push_back took me " << time_span.count() << " seconds.";
std::cout << std::endl;
vector<int> v2;
t1 = high_resolution_clock::now();
for(size_t i = 0; i < N; ++i)
v2.emplace_back(i);
t2 = high_resolution_clock::now();
time_span = duration_cast<duration<double>>(t2 - t1);
std::cout << "emplace_back took me " << time_span.count() << " seconds.";
std::cout << std::endl;
return 0;
}
Le résultat est que emplace_back
est plus rapide.
Push_back took me 2.76127 seconds.
emplace_back took me 1.99151 seconds.
Pourquoi? La réponse à la 1ère question liée indique clairement qu'il n'y aura pas de différence de performance.
A également essayé avec d'autres méthodes de temps de mon site pesudo, mais des résultats identiques.
[EDIT] Les commentaires disent que tester avec int
s ne dit rien et que Push_back
prend une réf.
J'ai fait le même test dans le code ci-dessus, mais au lieu de int
j'avais une classe A
:
class A {
public:
A(int a) : a(a) {}
private:
int a;
};
Résultat:
Push_back took me 6.92313 seconds.
emplace_back took me 6.1815 seconds.
[EDIT.2]
Comme l'a dit denlan, je devrais également changer la position des opérations, donc je les ai échangées et dans les deux situations (int
et class A
), emplace_back
était de nouveau le vainqueur.
[SOLUTION]
J'exécutais le code dans debug mode
, ce qui rend les mesures invalides. Pour l'analyse comparative, exécutez toujours le code dans release mode
.
Votre cas de test n'est pas très utile. Push_back
Prend un élément de conteneur et le copie/le déplace dans le conteneur. emplace_back
Prend des arguments arbitraires et construit à partir de ceux-ci un nouvel élément conteneur. Mais si vous passez un seul argument qui est déjà de type élément à emplace_back
, Vous utiliserez tout de même le constructeur copy/move.
Voici une meilleure comparaison:
Foo x; Bar y; Zip z;
v.Push_back(T(x, y, z)); // make temporary, Push it back
v.emplace_back(x, y, z); // no temporary, directly construct T(x, y, z) in place
La principale différence, cependant, est que emplace_back
Effectue des conversions explicites:
std::vector<std::unique_ptr<Foo>> v;
v.emplace_back(new Foo(1, 'x', true)); // constructor is explicit!
Cet exemple sera légèrement conçu à l'avenir, quand vous devriez dire v.Push_back(std::make_unique<Foo>(1, 'x', true))
. Cependant, d'autres constructions sont très sympas avec emplace
aussi:
std::vector<std::thread> threads;
threads.emplace_back(do_work, 10, "foo"); // call do_work(10, "foo")
threads.emplace_back(&Foo::g, x, 20, false); // call x.g(20, false)