Câu trả lời đơn giản là bạn nên viết mã cho các tham chiếu rvalue giống như mã tham chiếu thông thường và bạn nên đối xử với chúng giống nhau về mặt tinh thần 99% thời gian. Điều này bao gồm tất cả các quy tắc cũ về trả về tham chiếu (nghĩa là không bao giờ trả lại tham chiếu cho biến cục bộ).
Trừ khi bạn đang viết một lớp container mẫu cần tận dụng std :: Forward và có thể viết một hàm chung có tham chiếu lvalue hoặc rvalue, điều này ít nhiều đúng.
Một trong những lợi thế lớn đối với hàm tạo di chuyển và gán di chuyển là nếu bạn xác định chúng, trình biên dịch có thể sử dụng chúng trong các trường hợp là RVO (tối ưu hóa giá trị trả về) và NRVO (tối ưu hóa giá trị trả về) không được gọi. Điều này là khá lớn để trả về các đối tượng đắt tiền như container & chuỗi theo giá trị hiệu quả từ các phương thức.
Bây giờ, nơi mọi thứ trở nên thú vị với các tham chiếu rvalue, là bạn cũng có thể sử dụng chúng làm đối số cho các hàm bình thường. Điều này cho phép bạn viết các thùng chứa có quá tải cho cả tham chiếu const (const foo & khác) và tham chiếu giá trị (foo && khác). Ngay cả khi đối số quá khó sử dụng với lệnh gọi của hàm tạo đơn thuần, nó vẫn có thể được thực hiện:
std::vector vec;
for(int x=0; x<10; ++x)
{
// automatically uses rvalue reference constructor if available
// because MyCheapType is an unamed temporary variable
vec.push_back(MyCheapType(0.f));
}
std::vector vec;
for(int x=0; x<10; ++x)
{
MyExpensiveType temp(1.0, 3.0);
temp.initSomeOtherFields(malloc(5000));
// old way, passed via const reference, expensive copy
vec.push_back(temp);
// new way, passed via rvalue reference, cheap move
// just don't use temp again, not difficult in a loop like this though . . .
vec.push_back(std::move(temp));
}
Các thùng chứa STL đã được cập nhật để có quá tải di chuyển cho hầu hết mọi thứ (khóa băm và giá trị, chèn vectơ, v.v.) và là nơi bạn sẽ thấy chúng nhiều nhất.
Bạn cũng có thể sử dụng chúng cho các hàm bình thường và nếu bạn chỉ cung cấp một đối số tham chiếu giá trị, bạn có thể buộc người gọi tạo đối tượng và để cho hàm thực hiện di chuyển. Đây là một ví dụ hơn là sử dụng thực sự tốt, nhưng trong thư viện kết xuất của tôi, tôi đã gán một chuỗi cho tất cả các tài nguyên được tải, để dễ dàng xem mỗi đối tượng thể hiện điều gì trong trình gỡ lỗi. Giao diện giống như thế này:
TextureHandle CreateTexture(int width, int height, ETextureFormat fmt, string&& friendlyName)
{
std::unique_ptr<TextureObject> tex = D3DCreateTexture(width, height, fmt);
tex->friendlyName = std::move(friendlyName);
return tex;
}
Nó là một dạng 'trừu tượng bị rò rỉ' nhưng cho phép tôi tận dụng thực tế là tôi phải tạo ra chuỗi đã hầu hết thời gian và tránh tạo ra một bản sao khác của chuỗi. Đây không phải là mã hiệu suất cao chính xác nhưng là một ví dụ điển hình về khả năng khi mọi người hiểu rõ tính năng này. Mã này thực sự yêu cầu biến đó là tạm thời cho cuộc gọi hoặc std :: move được gọi:
// move from temporary
TextureHandle htex = CreateTexture(128, 128, A8R8G8B8, string("Checkerboard"));
hoặc là
// explicit move (not going to use the variable 'str' after the create call)
string str("Checkerboard");
TextureHandle htex = CreateTexture(128, 128, A8R8G8B8, std::move(str));
hoặc là
// explicitly make a copy and pass the temporary of the copy down
// since we need to use str again for some reason
string str("Checkerboard");
TextureHandle htex = CreateTexture(128, 128, A8R8G8B8, string(str));
nhưng điều này sẽ không được biên dịch!
string str("Checkerboard");
TextureHandle htex = CreateTexture(128, 128, A8R8G8B8, str);