2013-01-16 51 views
10

Trên bài viết Artima về tham chiếu rvalue C++ (http://www.artima.com/cppsource/rvalue.html) có các từ: Đó là lý do tại sao cần phải di chuyển (x) thay vì chỉ x khi chuyển xuống lớp cơ sở. Đây là một tính năng an toàn quan trọng của ngữ nghĩa di chuyển được thiết kế để ngăn chặn vô tình di chuyển hai lần từ một số biến được đặt tên.Tham chiếu Rvalue: Tại sao giá trị không được chuyển hoàn toàn?

Tôi không thể nghĩ rằng tình huống khi cử động kép đó có thể hoạt động. Bạn có thể đưa ra một ví dụ về điều này? Nói cách khác, điều gì sẽ xảy ra nếu tất cả các thành viên của T&& sẽ là các tham chiếu về giá trị và không chỉ là các tham chiếu?

Trả lời

16

Hãy xem xét kịch bản này:

void foo(std::string x) {} 
void bar(std::string y) {} 

void test(std::string&& str) 
{ 
    // to be determined 
} 

Chúng tôi muốn gọi foo với str, sau đó bar với str, cả với cùng một giá trị. Cách tốt nhất để làm điều này là:

foo(str); // copy str to x 
bar(std::move(str)); // move str to y; we move it because we're done with it 

Nó sẽ là một sai lầm để làm điều này:

foo(std::move(str)); // move str to x 
bar(std::move(str)); // move str to y...er, except now it's empty 

Bởi vì sau động thái đầu tiên giá trị của str là không xác định.

Vì vậy, trong thiết kế tài liệu tham khảo rvalue, động thái ẩn này không có ở đó. Nếu đúng như vậy, cách tốt nhất của chúng tôi ở trên sẽ không hoạt động vì đề cập đầu tiên là str sẽ là std::move(str) thay thế.

3

Con đường tôi nhìn thấy nó là nếu chúng ta đã có một số tài liệu tham khảo rvalue x:

T&& x = ...; 

và chúng tôi gọi một số chức năng sử dụng x như một tham số:

f(x) 

Chúng ta cần cách nọ cách kia để nói với f có hay không nó có thể làm hỏng x (hoặc "sở hữu x" hoặc "là khách hàng cuối cùng sử dụng x").

Một cách để thiết kế này sẽ được hội đủ điều kiện mỗi cuộc gọi:

f(yours_now(x)) // ok to damage 
f(still_mine(x)) // dont damage 

và thực hiện cuộc gọi không đủ điều kiện bất hợp pháp.

Một cách khác sẽ được thực hiện một cách mặc định:

Hoặc:

f(yours_now(x)) // ok to damage 
f(x) // dont damage 

hoặc

f(x) // ok to damage 
f(still_mine(x)) // dont damage 

Vì vậy, nếu chúng ta đồng ý đủ điều kiện mỗi lần sử dụng là quá cồng kềnh và chúng ta nên mặc định theo một cách, tốt nhất là gì? Vâng, hãy xem xét chi phí vô tình chọn mặc định trong cả hai trường hợp:

Trong trường hợp đầu tiên, bạn có thể bị hỏng, nhưng chúng tôi vô tình cho rằng không phải vậy. Trong trường hợp này chúng tôi mất hiệu suất vì một bản sao không cần thiết đã được thực hiện, nhưng khác hơn là không có việc lớn.

Trong trường hợp thứ hai không thể làm hỏng đối tượng, nhưng chúng tôi vô tình cho biết.Điều này có thể gây khó khăn trong việc phát hiện lỗi logic trong chương trình, vì x hiện đang ở trạng thái bị hỏng khi trả về f, nhưng tác giả mong đợi nó không được.

Vì vậy, trường hợp đầu tiên là những gì được chọn vì nó "an toàn hơn".

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