2014-05-17 11 views
22

Ich dachte, dass emplace_back würde der Sieger sein, wenn so etwas wie dies zu tun:Warum emplace_back ist schneller als push_back?

v.push_back(myClass(arg1, arg2)); 

weil emplace_back das Objekt sofort in dem Vektor konstruieren würde, während push_back, würde zunächst ein anonymes Objekt erstellen und kopieren Sie dann würde es der Vektor. Für mehr siehe this Frage.

Google gibt auch this und this Fragen.

Ich entschied mich, sie für einen Vektor zu vergleichen, der mit ganzen Zahlen gefüllt wäre. Hier

ist der Testcode:

#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; 
} 

Das Ergebnis ist, dass emplace_back schneller ist.

push_back took me 2.76127 seconds. 
emplace_back took me 1.99151 seconds. 

Warum? Die Antwort der ersten verknüpften Frage besagt eindeutig, dass es keinen Leistungsunterschied geben wird.

Auch mit anderen time methods von meiner Pesudo-Website versucht, aber identische Ergebnisse.

[EDIT] Kommentare sagen, dass das Testen mit int s nichts sagt und dass push_back eine ref.

habe ich den gleichen Test in dem obigen Code, aber statt int hatte ich eine Klasse A:

class A { 
public: 
    A(int a) : a(a) {} 
private: 
    int a; 
}; 

Ergebnis:

push_back took me 6.92313 seconds. 
emplace_back took me 6.1815 seconds. 

[EDIT.2]

Wie Denlan sagte, ich sollte auch die Position der Operationen ändern, also tauschte ich sie und in beiden Situationen (int und class A), emplace_back war wieder der Gewinner.

[SOLUTION]

ich den Code in debug mode ausgeführt wird, die die Messungen ungültig macht. Führen Sie den Code für das Benchmarking immer unter release mode aus.

Antwort

37

Ihr Testfall ist nicht sehr hilfreich. push_back nimmt ein Containerelement und kopiert/verschiebt es in den Container. emplace_back nimmt willkürliche Argumente und konstruiert daraus ein neues Containerelement. Übergeben Sie jedoch ein einzelnes Argument, das bereits einen Elementtyp aufweist, an emplace_back, verwenden Sie den Konstruktor copy/move trotzdem.

Hier ist ein besserer Vergleich:

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 

Der entscheidende Unterschied ist jedoch, dass emplace_backexplizite Konvertierungen durchführt:

std::vector<std::unique_ptr<Foo>> v; 
v.emplace_back(new Foo(1, 'x', true)); // constructor is explicit! 

Dieses Beispiel wird in Zukunft leicht gekünstelt sein, wenn Sie sollte sagen v.push_back(std::make_unique<Foo>(1, 'x', true)). Andere Konstruktionen sind aber auch sehr schön mit emplace:

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) 
Verwandte Themen