Là trở về bởi tham chiếu rvalue hiệu quả hơn?


Câu trả lời:


246
Beta_ab&&
Beta::toAB() const {
    return move(Beta_ab(1, 1));
}

Điều này trả về một tham chiếu lơ lửng, giống như với trường hợp tham chiếu lvalue. Sau khi hàm trả về, đối tượng tạm thời sẽ bị hủy. Bạn nên trả về Beta_abtheo giá trị, như sau

Beta_ab
Beta::toAB() const {
    return Beta_ab(1, 1);
}

Bây giờ, nó chuyển đúng một Beta_abđối tượng tạm thời vào giá trị trả về của hàm. Nếu trình biên dịch có thể, nó sẽ tránh di chuyển hoàn toàn, bằng cách sử dụng RVO (tối ưu hóa giá trị trả về). Bây giờ, bạn có thể làm như sau

Beta_ab ab = others.toAB();

Và nó sẽ di chuyển xây dựng tạm thời vào ab, hoặc làm RVO để bỏ qua việc di chuyển hoặc sao chép hoàn toàn. Tôi khuyên bạn nên đọc BoostCon09 Rvalue Reference Reference 101 để giải thích vấn đề và cách (N) RVO xảy ra để tương tác với điều này.


Trường hợp của bạn trả lại một tài liệu tham khảo giá trị sẽ là một ý tưởng tốt trong những dịp khác. Hãy tưởng tượng bạn có một getAB()chức năng mà bạn thường gọi tạm thời. Nó không tối ưu để làm cho nó trả về một tham chiếu const lvalue cho các giá trị tạm thời. Bạn có thể thực hiện nó như thế này

struct Beta {
  Beta_ab ab;
  Beta_ab const& getAB() const& { return ab; }
  Beta_ab && getAB() && { return move(ab); }
};

Lưu ý rằng movetrong trường hợp này không phải là tùy chọn, vì abkhông phải là tự động cục bộ cũng không phải là giá trị tạm thời. Bây giờ, trình phân loại giới thiệu && nói rằng hàm thứ hai được gọi trên các giá trị tạm thời, thực hiện bước di chuyển sau, thay vì sao chép

Beta_ab ab = Beta().getAB();

51
Tôi đã luôn cho rằng vấn đề tham chiếu lơ lửng tự động biến mất khi kiểu trả về là tham chiếu giá trị r. Vui mừng tôi đã nói thẳng ra trước khi nó cắn tôi. Đập vỡ bọ xít hút.
deft_code

31
:) Thực sự, tham chiếu rvalue là "chỉ tham chiếu" như tham chiếu lvalue. họ không sao chép hoặc lưu trữ bất cứ thứ gì.
Julian Schaub - litb

9
const & Qualifier trên chức năng thành viên nhiều hơn một const đơn giản là gì?
galinette


3
@galinette Đây là những vòng loại ref .
Malcolm

2

thể hiệu quả hơn, ví dụ, trong một bối cảnh hơi khác:

template <typename T>
T&& min_(T&& a, T &&b) {
    return std::move(a < b? a: b);
}

int main() {
   const std::string s = min_(std::string("A"), std::string("B"));
   fprintf(stderr, "min: %s\n", s.c_str());
   return 0;
}

Như một quan sát thú vị, trên máy của tôi clang++ -O3tạo ra 54 hướng dẫn cho mã ở trên so với 62 hướng dẫn cho thường xuyên std::min. Tuy nhiên, với -O0nó tạo ra 518 hướng dẫn cho mã ở trên so với 480 cho thường xuyên std::min.


Tôi bối rối trước câu trả lời của bạn. Đã thử một phiên bản (có thể) tương tự nhưng không thành công: ideone.com/4GyUbZ Bạn có thể giải thích tại sao không?
Đức Thanh

Bạn đã sử dụng tài liệu tham khảo về đối tượng tạm thời for(:)và tích hợp trên đối tượng bị hủy. Khắc phục: ideone.com/tQVOal
wonder.mice

3
câu trả lời này có thực sự sai không? đối với tham số mẫu T, T && không phải là tham chiếu giá trị r, mà là tham chiếu phổ quát, và trong trường hợp đó, chúng ta nên luôn gọi std :: Forward <T>, không phải std :: move! Chưa kể, câu trả lời này mâu thuẫn trực tiếp với câu hỏi được bình chọn hàng đầu ở trên.
xdavidliu

@xdavidliu câu trả lời này là một ví dụ dễ hiểu làm thế nào việc trả lại bằng rvalue có thể hiệu quả hơn. std::move()chỉ được sử dụng như một diễn viên rõ ràng để minh họa điểm rõ ràng hơn. Đây không phải là mã bạn sẽ sao chép-dán vào dự án của bạn. Nó không mâu thuẫn với câu trả lời được bình chọn hàng đầu, bởi vì có đối tượng tạm thời được tạo bên trong hàm. Ở đây, đối tượng trả về là một trong các đối số (các đối tượng tạm thời bị hủy là bước cuối cùng trong việc đánh giá biểu thức đầy đủ (về mặt từ vựng) chứa điểm mà chúng được tạo).
wonder.mice

2
@ wonder.mice sau đó vui lòng thay thế T bằng std :: string; Không cần sử dụng tất cả các mẫu ở đây và sử dụng T && làm tham chiếu giá trị r chỉ là phong cách khủng khiếp khiến mọi người nhầm lẫn mới với các mẫu và giá trị r.
xdavidliu
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.