Hãy xem xét các chức năng sau:tuyên bố Return bất thường
Widget f(Widget w) {
return w;
}
Giả sử Widget
thực hiện cả hai bản sao và di chuyển nhà thầu, theo tiêu chuẩn C++, w
phải được đối xử như một rvalue đối tượng trong câu lệnh return, trong trường hợp trình biên dịch sẽ không xem xét sao chép elision một lựa chọn tốt hơn.
Mặt khác, hãy xem xét các phiên bản dưới đây:
Widget f(Widget&& w) {
return w;
}
Như đối diện với phiên bản đầu tiên, theo Item 25
của Effective Modern C++
, tác giả dường như được ngụ ý rằng trở w
chắc chắn sẽ gọi constructor sao chép. Nói cách khác, ông đề nghị trả lại std::move(w)
thay vào đó, để làm cho trình biên dịch sử dụng hàm khởi động (có thể nhanh hơn).
bạn có thể giải thích lý do tại sao phiên bản thứ hai của f()
tham gia một Widget&&
như là đối số không tương đương với phiên bản đầu tiên tham gia một Widget
bởi giá trị đối với các nhà xây dựng với được gọi trong báo cáo lợi nhuận, thậm chí còn nghĩ rằng trong cơ thể của cả hai các chức năng biểu thức w
đề cập đến một lvalue
?
dụ Complete chứng minh hành vi:
#include <iostream>
struct Widget
{
Widget() { std::cout << "constructed" << std::endl; }
~Widget() { std::cout << "destructed" << std::endl; }
Widget(const Widget&) { std::cout << "copy-constructed" << std::endl; }
Widget(Widget&&) { std::cout << "move-constructed" << std::endl; }
};
Widget
f1(Widget w)
{
return w;
}
Widget
f2(Widget&& w)
{
return w;
}
int
main()
{
f1(Widget {});
std::cout << std::endl;
f2(Widget {});
}
Output:
constructed
move-constructed
destructed
destructed
constructed
copy-constructed
destructed
destructed
Cả hai w trong 'return w' đều là các giá trị (có thể là bản sao được trả về). Sự khác biệt chính là các đối số hàm, đầu tiên là một bản sao (!) Thứ hai không. Áp dụng một std :: di chuyển đến hàm thứ hai nên làm cho nó (gần như?) Một noop. –
@MattMcNabb Nó thực sự là đúng. Có một ngoại lệ cho các tài liệu tham khảo, phải có.Làm cho 'Widget f (Widget & w) {return w; } 'di chuyển âm thầm sẽ nguy hiểm. Bây giờ, ngoại lệ đó * có thể * sẽ ổn nếu nó chỉ dành cho các tham chiếu lvalue, nhưng nó chỉ đơn giản là cho mọi thứ không được biết là an toàn để di chuyển. – hvd
@hvd 'return w;' luôn sao chép đối số vào giá trị trả về - bất kể đó là 'Widget w',' Widget & w' hoặc 'Widget && w'. (Ít nhất, đó là những gì trình biên dịch của tôi đang nói với tôi) .Giá trị trả về có thể được chuyển vào đối tượng được gán cho nó; động thái đó thường được ưu tiên. –