2017-08-25 26 views
21

Xét đoạn mã sau:Tại sao các nhà xây dựng sao chép và di chuyển được gọi cùng nhau?

#include <iostream> 
#include <vector> 
using namespace std; 

class A 
{ 
public: 
    A(int) { cout << "int" << endl; } 
    A(A&&) { cout << "move" << endl; } 
    A(const A&) { cout << "copy" << endl; } 
}; 

int main() 
{ 
    vector<A> v 
    { 
     A(10), A(20), A(30) 
    }; 

    _getch(); 
    return 0; 
} 

Đầu ra là:

int 
int 
int 
copy 
copy 
copy 

A(10), A(20)A(30) là temporaries, phải không?

Vậy tại sao trình tạo bản sao lại được gọi? Không nên gọi hàm khởi động thay vào đó?

Đi qua move(A(10)), move(A(20)), move(A(30)) thay vào đó, đầu ra là:

int 
move 
int 
move 
int 
move 
copy 
copy 
copy 

Trong trường hợp này hoặc sao chép hoặc di chuyển constructor được gọi.

Điều gì đang xảy ra?

+7

Bạn không thể di chuyển từ các phần tử 'initializer_list'. 'Di chuyển' bổ sung trong ví dụ thứ hai của bạn ngăn cản việc sao chép bản sao và vì vậy bạn sẽ có thêm một bước di chuyển trên đầu trang của bản sao. –

+1

Câu hỏi hay; câu trả lời được chôn ở đây: http://en.cppreference.com/w/cpp/language/list_initialization – Bathsheba

+1

Bên trong một hàm tạo có 'std :: initializer_list' trong' std :: vector', những phần tử đó không còn là giá trị . –

Trả lời

14

std::vector có thể được xây dựng từ std::initializer_list và bạn đang gọi hàm tạo đó. Các quy tắc cho nhà nước xây dựng initializer_list rằng constructor này đang tích cực ưa thích:

Một constructor là một initializer-list constructor nếu tham số đầu tiên của nó là loại std::initializer_list<E> hoặc tài liệu tham khảo để có thể cv-trình độ std::initializer_list<E> đối với một số loại E và có hoặc không có tham số hoặc các tham số khác có đối số mặc định (8.3.6). [Ghi chú: Initializer-list nhà xây dựng được ưu tiên hơn nhà xây dựng khác trong danh sách-khởi < ...>]

Ngoài ra, do các loại thực hiện kỳ ​​lạ của một initializer_list như một mảng phân bổ dưới mui xe, các yếu tố của mảng tương ứng rằng std::initializer_list<E> đề cập đến buộc phải được sao chép khởi tạo (có thể được elided):

một đối tượng của loại std::initializer_list<E> được xây dựng từ một danh sách initializer như thể việc thực hiện phân bổ một mảng của N yếu tố của loại E, trong đó N là số phần tử trong danh sách bộ khởi tạo. Mỗi phần tử của mảng đó là sao chép khởi tạo với các yếu tố tương ứng của danh sách initializer, và đối tượng std::initializer_list<E> được xây dựng để đề cập đến mảng

(Cả hai tài liệu tham khảo trên từ N3337 [dcl.init.list] Tuy nhiên, trong ví dụ đầu tiên của bạn, bản sao có thể/là elided mặc dù tên ([dcl.init]/14) để bạn không thấy bản sao phụ (chúng cũng có thể được di chuyển) Bạn có thể cảm ơn trình biên dịch của bạn cho rằng, bởi vì bản sao elision là không cần thiết trong C++ 11 (mặc dù nó là trong C++ 17).

Xem [class.copy] để biết thêm chi tiết ("Khi đáp ứng các tiêu chí nhất định, việc triển khai được phép bỏ qua việc sao chép/di chuyển của đối tượng lớp ...").

Phần cuối cùng là chìa khóa:

[support.initlist] bang mà

Một đối tượng của loại initializer_list<E> cung cấp quyền truy cập vào một mảng các đối tượng của loại const E.

Điều này có nghĩa là std::vector không thể vượt qua bộ nhớ một cách trực tiếp; nó phải được sao chép, đây là nơi bạn cuối cùng nhìn thấy các công trình sao chép được gọi.

Trong ví dụ thứ hai, đó là Kerrek SB đã nêu, bạn đã ngăn chặn bản sao mà tôi đã đề cập trước đó và gây thêm phí di chuyển.

+0

Có vẻ như một 'vector (std :: initializer_list &&)' sẽ hữu ích :( –

5

A (10), A (20), A (30) là tạm thời, phải không?

Đúng.

Vậy tại sao trình tạo bản sao được gọi? Không nên gọi hàm khởi động thay vào đó?

Thật không may, không thể di chuyển từ std::initializer_list, đó là những gì mà nhà xây dựng này sử dụng std::vector.

di chuyển Đi qua (A (10)), di chuyển (A (20)), di chuyển (A (30)) thay vì

Trong trường hợp này hoặc sao chép hoặc di chuyển constructor được gọi. Chuyện gì vậy?

Vì chuyển đổi std::move ngăn cản việc sao chép và do đó các thành phần của std::initializer_list được di chuyển mà không cần phải cắt bỏ. Sau đó, hàm tạo của các bản sao vector từ danh sách.

Các vấn đề liên quan