2013-02-13 24 views
17
auto&& mytup = std::make_tuple(9,1,"hello"); 
    std::get<0>(mytup) = 42; 
    cout << std::get<0>(mytup) << endl; 
  1. Có bản sao/di chuyển liên quan (không có RVO) khi trở về từ make_tuple không?
  2. Ứng dụng có gây ra hành vi không xác định không?
  3. Tôi có thể đọc cả viết tham chiếu chung. Có thể sử dụng số auto&& var = func() thay vì auto var = func() để không có sao chép/di chuyển không?
+0

Tham chiếu là tham chiếu. –

+0

về 'auto && var = func()', http://stackoverflow.com/questions/13618506/is-it-possible-to-stdmove-objects-out-of-functions-c11/13618587#13618587 – billz

+3

@billz link là một trường hợp khác khi nó trả về biến cục bộ làm tham chiếu. Lỗi là bên trong hàm không phải nơi nó được gọi. – balki

Trả lời

7
  1. Yes. Bất kỳ trở về từ một chức năng mà không trả lại một loại tham chiếu có thể liên quan đến một bản sao/di chuyển. Cho biết đó là những gì RVO là về. Các đối tượng mà bạn tham khảo là ràng buộc để cần phải được khởi tạo bằng cách nào đó.

  2. No. Tại sao phải không? Thời gian tồn tại của một giá trị tạm thời/giá trị được liên kết với tham chiếu được xác định bởi phạm vi của tham chiếu.

  3. Nếu func() không trả về một loại tài liệu tham khảo, không nên có bất kỳ sự khác biệt trong hiệu quả (nếu không hành vi)

giữa

auto&& var = func(); 

auto var = func(); 

Trong cả hai trường hợp, một đối tượng có tuổi thọ đến cuối khối chứa được xây dựng. Trong một trường hợp nó có tên riêng của nó, mặt khác nó được đặt tên thông qua một tham chiếu. Trong cả hai trường hợp, tên có thể được sử dụng như một giá trị. RVO có thể được ứng dụng tốt trong cả hai trường hợp.

Một số trình biên dịch có thể tối ưu hóa tốt hơn cho đối tượng địa phương so với tham chiếu, mặc dù trong trường hợp hiện tại, tham chiếu đến tạm thời thực sự không khác với đối tượng cục bộ.

Nếu func() có thể trả lại tham chiếu, mọi thứ khác nhau nhiều - trong trường hợp đó bạn phải quyết định xem bạn có muốn sao chép/di chuyển hay không.

+0

Nếu func xảy ra để trả về một giá trị như 'Foo & func()', 'auto &&' phiên bản sẽ không sao chép trong khi 'auto' sẽ sao chép – balki

+0

@balki: Nhưng chúng tôi đã thảo luận về hàm trả về giá trị tại đây. Bây giờ tôi đã phân biệt rõ ràng. – JoergB

+0

"Tuổi thọ của giá trị tạm thời/giá trị được liên kết với tham chiếu được xác định bởi phạm vi của tham chiếu". mới này trong C++ 11? Trong c + 03, điều này chỉ đúng với tham chiếu const. – Suma

0

Kết quả đánh giá cuộc gọi đến make_tuple là tạm thời giá trị của bản sao kê tuple. autoloại-specifier sẽ được suy ra như cùng một tuple instantiation (7.1.6.4p6), vì vậy mytup thuộc loại tuple<...> &&. Giá trị tạm thời prvalue sau đó được kéo dài suốt đời bằng tham chiếu mytup (12.2p5).

  1. Bởi vì tạm thời giá trị trả về của hàm, không có sao chép/di chuyển liên quan (Vẫn có thể RVO trong make_tuple).
  2. Hành vi được xác định đầy đủ.
  3. Trong hầu hết các trường hợp, mytup sẽ được coi là giá trị mặc dù loại của nó là tham chiếu giá trị. Tuy nhiên, không có điểm nào sử dụng auto && vì tất cả các trình biên dịch hợp lý sẽ tách rời bản sao/di chuyển khỏi tạm thời.

Để làm rõ, khoảng cách duy nhất để có mytup coi là một rvalue là sử dụng std::forward<decltype(mytup)>(mytup), như trong What does auto&& tell us?; tuy nhiên nếu bạn biết loại mytup (tuple<...> trong trường hợp này) thì bạn cũng có thể sử dụng std::move.

14

Chỉ có vấn đề trong trường hợp trình khởi tạo là cuộc gọi hàm trả về tham chiếu rvalue trong thời gian ngắn. Với ít từ hơn và nhiều mã hơn:

// Fine; lifetime extension applies! 
auto&& ref = 42; 

auto id = [](int&& i) -> int&& { return std::move(i); }; 
auto&& uhoh = id(42); 
// uhoh is now a stale reference; can't touch it! 

Ngược lại, auto uhoh = id(42); sẽ hoạt động tốt.

Trong trường hợp của bạn, vì std::make_tuple trả về một giá trị và không phải là tham chiếu rvalue, không có vấn đề gì.

Tôi cho rằng nguy hiểm thực sự là từ các hàm và mẫu chức năng với tham số tham chiếu rvalue và trả về tham chiếu rvalue cho tham số rvalue hoặc tham số phụ thuộc vào chúng. (Điều đó được nói, một cái gì đó đơn giản như auto&& ref = std::move(42); trình bày vấn đề!)

Tình hình không hoàn toàn mới từ C++ 11, xem xét: T const& ref = bar(T_factory());.

+4

+1, tôi nhớ trở ngại về 'T const & pass (T const & t) {return t; } 'ví dụ khi cố gắng cải thiện phát hiện của Clang về tham chiếu trở về thời gian ... thật không may là nó yêu cầu phân tích liên thủ tục để phát hiện * vấn đề có thể *: x –

0

Có quy tắc cụ thể trong C++ (ngay cả trước C++ 11) cho biết rằng nếu bạn ràng buộc tham chiếu đến thời gian tạm thời của thời gian tạm thời sẽ được kéo dài đến thời gian tồn tại của tham chiếu.

Một trường hợp đơn giản là:

int foo() { 
    return 42; 
} 

int bar() { 
    const int& x = foo(); 
    return x; // Here is safe to use x 
} 
+2

Quy tắc chỉ dành cho tham chiếu const. Tôi không nghĩ rằng nó là tự động rõ ràng && là một tham chiếu const - là nó? – Suma

+0

@Suma: Tham chiếu là tham chiếu cho trình biên dịch back-end. Const-correctness chỉ ảnh hưởng đến front-end (những gì là hợp pháp và những gì không) và không đóng vai trò trong hành vi không xác định hoặc về hiệu suất. – 6502

+0

Có vẻ như tôi đã sai. Tôi không thể thấy bất cứ điều gì về const trong tiêu chuẩn, câu tương ứng nói "khi một tham chiếu bị ràng buộc với một tạm thời" trong 12.2, ít nhất là trong bản thảo C++ 11. Hướng dẫn nói về const &, nhưng đó có thể là vì một đồng bằng & không thể bị ràng buộc vào một tạm thời anyway. – Suma