2016-01-19 16 views
13

Định nghĩa của Xvalue được như sau:Khi nào chúng ta thực sự cần 'xvalues ​​rõ ràng'?

- Một Xvalue (một “hết hạn” giá trị) cũng đề cập đến một đối tượng, thường là gần cuối cuộc đời của mình (để các nguồn lực của nó có thể được di chuyển, ví dụ). Một xvalue là kết quả của một số loại biểu thức liên quan đến tham chiếu rvalue (8.3.2). [Ví dụ: Kết quả của việc gọi một hàm có kiểu trả về là tham chiếu rvalue là xvalue. —end example]

Chúng ta có bao giờ rơi vào nơi mà thực tế chúng ta cần sử dụng hàm có kiểu trả về là tham chiếu rvalue, giá trị xvalue không?

const int && Foo() 
{ 
    // ... 
} 

Di chuyển ngữ nghĩa tham chiếu rvalue làm tham số chứ không phải giá trị trả về. Vì vậy, tôi không nghĩ rằng đó là trường hợp.

+0

ý của bạn là "rõ ràng" trong tiêu đề? –

+0

@ M.M Nếu tôi viết một hàm trả về xvalue và tôi 'nhận thức' nó, và đó là dự định của tôi, tôi muốn nói điều đó rõ ràng mặc dù không có từ khóa cú pháp nào để chỉ xvalues. –

Trả lời

4

Tham chiếu rvalue trả về có thể được sử dụng cho các hàm đã lấy giá trị làm tham số. Một ví dụ đơn giản:

struct X { 
    X() = default; 
    X(X&& other) { std::cout << "move ctor\n"; } 
    X(X const&) = delete; 
    void log(std::string const& s){ std::cout << "log: " << s << "\n"; } 
}; 

void sink(X&& x) { 
    x.log("sink"); 
} 

X&& passOn(X&& in) { 
    in.log("pass"); 
    return std::move(in); 
} 

X moveOn(X&& in) { 
    in.log("move"); 
    return std::move(in); 
} 

int main() { 
    sink(passOn(X())); 
    std::cout << "===============================\n"; 
    sink(moveOn(X())); 
} 

Live demo →

Chức năng thứ hai sẽ gọi constructor di chuyển để tạo ra các đối tượng quay trở lại, trong khi người đầu tiên sẽ vượt qua trên tham chiếu nó đã có. Điều này hữu ích hơn nếu chúng tôi không trả lại tham chiếu ban đầu mà thay vào đó là tham chiếu đến một phần của đối tượng được giới thiệu, ví dụ:

template<class T> 
T&& getHead(std::vector<T>&& input) { 
    return std::move(input.front()); 
} 
+0

@ Jarod42 Không di chuyển ở đây sẽ gọi hàm tạo bản sao đã xóa. Tôi không chắc chắn nếu NRVO sẽ áp dụng ở tất cả, vì không có đối tượng bên trong chức năng. –

+0

Hữu ích cho các chức năng bộ lọc được chuyển tiếp hoàn hảo. +1! –

5

Đó chính xác là những gì std::move là - kết quả của việc thực hiện std::move là một xvalue. Khác hơn là nó rất khó để nói kể từ trong chính trở về một tài liệu tham khảo từ chức năng là một điều xấu hầu hết thời gian. Nhưng có thể ai đó sẽ đưa ra một cách sử dụng thông minh khác của một chức năng như vậy.

+0

@DeanSeo, thực sự nhưng bạn không thể sử dụng tham chiếu rvalue trong kiểu trả về cho bất kỳ điều gì khác ngoại trừ việc truyền kể từ khi trả về tham chiếu (cho dù đó là kiểu gì) từ hàm là sai, trừ nếu nó là tham chiếu const và const rvalue là vô ích – ixSci

+0

Xin lỗi vì đã xóa nhận xét trước của tôi.Btw, 'tham chiếu const rvalue đang được trả về' là một xvalue. Vì vậy, đệ quy, trả lại xvalues ​​là thực tế vô dụng, bạn nói? : p –

+0

@DeanSeo, điều tôi đang nói là trả lại tham chiếu đến nội dung được tạo trên ngăn xếp trong một hàm không chính xác. Vì vậy, tôi không thấy ví dụ sử dụng khi chúng ta có thể sử dụng tham chiếu rvalue làm kiểu trả về ngoại trừ trường hợp chúng ta có 'std :: move' (chúng ta có thứ gì đó từ bên ngoài và trả về giá trị rvalue). Nó không có nghĩa là không phải là một sử dụng như vậy - các tính năng ngôn ngữ được tái khám phá một lần nữa và một lần nữa. Nhưng bây giờ tôi nghe nói về không có gì trong vấn đề này. – ixSci

3

Chúng ta có bao giờ rơi vào nơi mà thực tế chúng ta cần sử dụng hàm có kiểu trả về là tham chiếu rvalue, giá trị xvalue không?

Nó được sử dụng trong các lớp container, ví dụ tuple có một tình trạng quá tải get trông như thế này:

template< std::size_t I, class... Types > 
typename std::tuple_element<I, tuple<Types...> >::type&& 
    get(tuple<Types...>&& t); 

tôi cho rằng std::optionalstd::variant trong C++ 17 cả hai sẽ có một quá tải tương tự.

Cấp, điểm duy nhất là để tránh phải gõ std::move trong một số tình huống rất cụ thể, như:

auto x = std::get<1>(f()); 

đâu f trả về một tuple theo giá trị.

+0

Một ví dụ tuyệt vời về cách lưu các nhà xây dựng ngay cả khi chúng không cần thiết (tức là về mặt lý thuyết nó có thể vừa trả về các xvalues ​​được chuyển đổi thành giá trị, nhưng điều đó sẽ đòi hỏi, không cần thiết, hoặc là một công cụ chuyển đổi hoặc sao chép. t luôn luôn có sẵn). –

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