2011-08-09 33 views
40

Thứ nhất, tôi biết là this question, nhưng tôi không tin rằng tôi đang yêu cầu điều tương tự.Tại sao push_back không thể bị quá tải để thực hiện công việc của emplace_back?

Tôi biết những gì std::vector<T>::emplace_backkhông - và tôi hiểu tại sao tôi sẽ sử dụng nó trên push_back(). Nó sử dụng các mẫu variadic cho phép tôi chuyển tiếp nhiều đối số tới hàm tạo của một phần tử mới.

Nhưng điều tôi không hiểu là tại sao ủy ban tiêu chuẩn C++ quyết định có nhu cầu cho một chức năng thành viên mới. Tại sao họ không thể mở rộng chức năng của push_back(). Theo như tôi thấy, push_back có thể bị quá tải trong C++ 11 là:

template <class... Args> 
void push_back(Args&&... args); 

này sẽ không phá vỡ tính tương thích ngược, đồng thời cho phép bạn để vượt qua đối số N, bao gồm lập luận rằng sẽ gọi một rvalue bình thường hoặc copy constructor. Trong thực tế, GCC C++ 11 thực hiện push_back() chỉ đơn giản gọi emplace_back anyway:

void push_back(value_type&& __x) 
    { 
    emplace_back(std::move(__x)); 
    } 

Vì vậy, cách tôi nhìn thấy nó, không có nhu cầu cho emplace_back(). Tất cả những gì họ cần thêm là quá tải cho push_back() chấp nhận đối số variadic và chuyển tiếp các đối số tới hàm tạo phần tử.

Tôi có sai ở đây không? Có lý do nào đó cần một chức năng hoàn toàn mới ở đây không?

+1

trông giống như sau: http://stackoverflow.com/questions/4303513/push-back-vs-emplace-back – moka

+7

Câu hỏi hay. @moka anh ấy biết sự khác biệt giữa những gì hai chức năng làm. Anh thậm chí còn liên kết với câu hỏi cụ thể đó. –

+0

Họ có ý nghĩa khác nhau, tất cả đều được giải thích trong câu hỏi bạn đã đề cập bạn đọc. So sánh 'v.emplace_back (123)' và 'v.push_back (123)' ví dụ cho 'vector v;' với chuyển đổi ngầm từ 'int'. –

Trả lời

38

Nếu T có một hàm tạo chuyển đổi rõ ràng, có hành vi khác nhau giữa emplace_backpush_back.

struct X 
{ 
    int val; 
    X() :val() {} 
    explicit X(int v) :val(v) {} 
}; 

int main() 
{ 
    std::vector<X> v; 
    v.push_back(123); // this fails 
    v.emplace_back(123); // this is okay 
} 

Thực hiện thay đổi bạn đề xuất có nghĩa là push_back sẽ hợp pháp trong trường hợp đó và tôi cho rằng đó không phải là hành vi mong muốn. Tôi không biết đây có phải là lý do hay không, nhưng đó là điều duy nhất tôi có thể nghĩ ra.

+7

Nó đặc biệt hữu ích khi xử lý các thùng chứa 'unique_ptr', vì 'v.emplace_back (new foo)' đơn giản hơn nhiều so với 'v.push_back (std :: unique_ptr (new foo))'. Nhưng người ta có thể * yêu cầu một cách rõ ràng * chuyển đổi trong trường hợp này. –

+0

@AlexandreC: Trên thực tế, 'emplace_back (new foo)' không phải là ngoại lệ an toàn, do đó, đó là điều sai trái để làm. – Mehrdad

+0

@Mehrdad bạn có nghĩa là vì phân bổ có thể có thể thất bại? Heck đó là sự thật ... –

1

Đây là một ví dụ khác.

Thành thực mà nói, hai là ngữ nghĩa nên khác nhau, đó là hành vi tương tự của họ nên được coi là một chỉ trùng hợp ngẫu nhiên (do thực tế rằng C++ có "nhà xây dựng bản sao" với một cú pháp đặc biệt).

Bạn thực sự cần không sử dụng emplace_back trừ khi bạn muốn tại chỗ-xây dựng ngữ nghĩa.
Rất hiếm khi bạn cần một thứ như vậy. Nói chung push_back là những gì bạn thực sự, ngữ nghĩa muốn.

#include <vector> 

struct X { X(struct Y const &); }; 
struct Y { Y(int const &); operator X(); }; 

int main() 
{ 
    std::vector<X> v; 
    v. push_back(Y(123)); // Calls Y::operator X() and Y::Y(int const &) 
    v.emplace_back(Y(123)); // Calls X::X(Y const &) and Y::Y(int const &) 
} 
Các vấn đề liên quan