2015-01-07 16 views
18

Tại sao gọi std :: di chuyển trên đối tượng const gọi hàm tạo bản sao khi được truyền cho một đối tượng khác? Cụ thể, mãTại sao gọi std :: di chuyển trên đối tượng const gọi hàm tạo bản sao khi được truyền cho đối tượng khác?

#include <iostream> 

struct Foo { 
    Foo() = default; 
    Foo(Foo && x) { std::cout << "Move" << std::endl; } 
    Foo(Foo const & x) = delete; 
}; 

int main() { 
    Foo const x; Foo y(std::move(x)); 
} 

thất bại trong việc biên dịch với thông điệp:

g++ -std=c++14 test07.cpp -o test07 
test07.cpp: In function 'int main()': 
test07.cpp:10:36: error: use of deleted function 'Foo::Foo(const Foo&)' 
    Foo const x; Foo y(std::move(x)); 
            ^
test07.cpp:6:5: note: declared here 
    Foo(Foo const & x) = delete; 
    ^
Makefile:2: recipe for target 'all' failed 
make: *** [all] Error 1 

Chắc chắn, tôi hy vọng nó sẽ thất bại bởi vì chúng tôi không thể di chuyển một giá trị const. Đồng thời, tôi không hiểu được con đường mà đoạn mã lấy trước khi nó cố gắng gọi hàm tạo bản sao. Có nghĩa là, tôi biết rằng std::move chuyển đổi phần tử thành giá trị x, nhưng tôi không biết mọi thứ diễn ra như thế nào sau đó đối với const.

+7

Lệnh 'const'ness của xúc động đối tượng không thay đổi, 'Foo const &&' không thể liên kết với 'Foo &&' để trình biên dịch cố gắng truy cập vào hàm tạo bản sao, không thành công vì nó bị xóa. – user657267

+2

Tôi không có chuyên gia về các toán tử di chuyển, nhưng có thể là bạn có thể gọi di chuyển trên giá trị 'const', nhưng kết quả từ đó chỉ có thể được chấp nhận vào hàm tạo bản sao, do đó trình biên dịch quyết định gọi đó. – BWG

+1

"Có nghĩa là, tôi biết rằng std :: di chuyển chuyển đổi phần tử thành giá trị x" Thực ra, nó không. Nó trả về một tham chiếu rvalue cho item. –

Trả lời

35

Loại kết quả gọi std::move với đối số T constT const&&, không thể liên kết với thông số T&&. Trận đấu tốt nhất tiếp theo là nhà xây dựng bản sao của bạn, được xóa, do đó lỗi.

Rõ ràng delete nhập hàm không có nghĩa là không có sẵn để phân giải quá tải, nhưng nếu đó thực sự là ứng cử viên khả thi nhất được chọn bằng độ phân giải quá tải thì đó là lỗi trình biên dịch.

Kết quả có ý nghĩa vì việc xây dựng di chuyển là một hoạt động đánh cắp tài nguyên từ đối tượng nguồn, do đó biến đổi nó, vì vậy bạn không thể thực hiện điều đó với đối tượng const chỉ cần gọi std::move.

10

Loại std::move(x)Foo const&& không thể liên kết với Foo&&. Lý do cũng giống như đối với một số T const& không thể liên kết với một số T&. Tuy nhiên, bạn có thể có một hàm tạo dùng một số Foo const&&. Nhiều khả năng bạn sẽ không thể thực sự di chuyển dữ liệu đối tượng tương ứng nhưng, ví dụ, trong ví dụ của bạn có dữ liệu, ví dụ, đoạn mã sau hoạt động OK:

#include <iostream> 

struct Foo { 
    Foo() = default; 
    Foo(Foo &&) { std::cout << "Move\n"; } 
    Foo(Foo const&&) { std::cout << "Move const\n"; } 
    Foo(Foo const &) = delete; 
}; 

int main() { 
    Foo const x; Foo y(std::move(x)); 
} 
Các vấn đề liên quan