2014-05-17 20 views
22

Myślałem, że emplace_back będzie zwycięzcą, gdy robi coś takiego:Dlaczego emplace_back jest szybszy niż push_back?

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

ponieważ emplace_back natychmiast budowę obiektu w wektorze, natomiast push_back, najpierw skonstruować anonimowy obiekt, a następnie będzie go skopiować do wektor. Aby uzyskać więcej informacji, zobacz pytanie: this.

Google daje także pytania o this i this.

Postanowiłem porównać je dla wektora, który byłby wypełniony przez liczby całkowite.

Oto kod eksperyment:

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

Powoduje to, że emplace_back jest szybsze.

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

Dlaczego? Odpowiedź na pierwsze połączone pytanie jasno mówi, że nie będzie różnicy w wydajności.

Próbowałem także z innym time methods z mojej strony pesudo, ale identyczne wyniki.

[EDIT] Komentarze mówią, że testowanie z int s nic nie mówi i że push_back przyjmuje ref.

że sam ten sam test w kodzie powyżej, ale zamiast int miałem klasy A:

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

Wynik:

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

[EDIT.2]

jako denlan powiedział, że powinienem również zmienić pozycję operacji, więc zamieniłem je iw obu sytuacjach (int i class A), emplace_back ponownie wygrał.

[Rozwiązanie]

ja działania kodu w debug mode, co powoduje nieprawidłowe pomiary. W przypadku testów porównawczych zawsze uruchamiaj kod w release mode.

Odpowiedz

37

Twój przypadek testowy nie jest bardzo pomocny. push_back pobiera element kontenera i kopiuje/przenosi go do kontenera. emplace_back pobiera dowolne argumenty i konstrukcje z nowego elementu kontenera. Ale jeśli przekażesz pojedynczy argument, który już jest typu element do emplace_back, po prostu użyjesz konstruktora kopiowania/przenoszenia.

Oto lepsze porównanie:

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 

Kluczową różnicą jest jednak to, że emplace_back wykonuje wyraźne konwersji:

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

Ten przykład będzie łagodnie wymyślony w przyszłości, kiedy powinien powiedzieć v.push_back(std::make_unique<Foo>(1, 'x', true)). Jednak inne konstrukcje są bardzo ładne z emplace, też:

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) 
Powiązane problemy