2014-05-17 52 views
22

Tôi nghĩ rằng emplace_back sẽ là người chiến thắng, khi làm một cái gì đó như thế này:Tại sao emplace_back nhanh hơn push_back?

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

emplace_back sẽ xây dựng các đối tượng ngay lập tức trong vector, trong khi push_back, đầu tiên sẽ xây dựng một đối tượng ẩn danh và sau đó sẽ sao chép nó vào vectơ. Để biết thêm, hãy xem câu hỏi this.

Google cũng cung cấp cho thisthis câu hỏi.

Tôi quyết định so sánh chúng cho một véc tơ sẽ được lấp đầy bởi các số nguyên.

Đây là mã thử nghiệm:

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

Kết quả là emplace_back là nhanh hơn.

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

Tại sao? Câu trả lời của câu hỏi được liên kết đầu tiên nói rõ ràng rằng sẽ không có sự khác biệt về hiệu suất.

Cũng đã thử với một số khác là time methods từ trang web giả của tôi, nhưng kết quả giống hệt nhau.

[EDIT] Nhận xét nói rằng thử nghiệm với int s không nói bất cứ điều gì và rằng push_back có một ref.

tôi đã làm bài kiểm tra tương tự trong đoạn mã trên, nhưng thay vì int Tôi đã có một lớp A:

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

Kết quả:

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

[EDIT.2]

Như denlan nói, tôi cũng nên thay đổi vị trí của các hoạt động, vì vậy tôi đổi chỗ họ và trong cả hai tình huống (intclass A), emplace_back lại là người chiến thắng.

[SOLUTION]

Tôi đã chạy mã trong debug mode, mà làm cho các phép đo không hợp lệ. Để đo điểm chuẩn, hãy luôn chạy mã trong release mode.

Trả lời

37

Trường hợp thử nghiệm của bạn không hữu ích. push_back lấy phần tử vùng chứa và sao chép/di chuyển nó vào vùng chứa. emplace_back lấy các đối số và cấu trúc tùy ý từ những phần tử vùng chứa mới. Nhưng nếu bạn vượt qua một đối số duy nhất đã thuộc loại phần tử là emplace_back, thì bạn sẽ chỉ sử dụng hàm tạo bản sao/di chuyển.

Dưới đây là một so sánh tốt hơn:

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 

Sự khác biệt quan trọng, tuy nhiên, đó là emplace_back thực hiện rõ ràng chuyển đổi:

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

Ví dụ này sẽ được nhẹ giả tạo trong tương lai, khi bạn nên nói v.push_back(std::make_unique<Foo>(1, 'x', true)). Tuy nhiên, các công trình xây dựng khác rất đẹp với emplace, quá:

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) 
Các vấn đề liên quan