2012-01-12 40 views
24

§27.7.3.9 xác định tình trạng quá tải sau cho operator<<:Tại sao quá tải rvalue của `toán tử <<` cho `basic_ostream` trả về một tham chiếu lvalue?

template <class charT, class traits, class T> 
    basic_ostream<charT, traits>& 
    operator<<(basic_ostream<charT, traits>&& os, const T& x); 

Effects:os << x
Returns:os

(§27.7.2.6 xác định tình trạng quá tải rvalue cho operator>>.)
Về cơ bản, nó chỉ chuyển tiếp đến một quá tải lvalue. Tôi xem xét tình trạng quá tải này là khá nguy hiểm (các istream một thậm chí nhiều hơn so với các ostream một, trên thực tế), hãy xem xét những điều sau đây:

#include <sstream> 
#include <iostream> 

int main(){ 
    auto& s = (std::stringstream() << "hi there!\n"); 
    std::cout << s.rdbuf(); // oops 
} 

Live example on Ideone (ví dụ hoàn hảo của hành vi undefined Prints gì đối với tôi trên MSVC10.).

Ví dụ trên có thể trông giả tạo, nhưng nó không phải là quá khó khăn để có được vào tình trạng này trong mã chung hoặc khi đi qua các (std::stringstream() << "text") đến một chức năng cung cấp một giá trị trái và một tình trạng quá tải rvalue và lưu trữ các std::ostream hoặc std::istream trong các cách khác nhau theo tình trạng quá tải.

Bây giờ, đối số sẽ lặp lại một số basic_ostream<charT, traits>&& và chỉ định những điều sau đây là gì?

Returns: (. Và tương tự cho basic_istream) di chuyển (os)

Có điều gì tôi nhìn ra? Ở trạng thái hiện tại, trong mắt tôi, nó trông có vẻ nguy hiểm và giống như một khiếm khuyết. Tôi lướt qua số LWG issue list và tìm thấy this proposal (hi @HowardHinnant!). Nó thực sự trả về một rvalue, tuy nhiên chỉ vì lợi ích bổ sung của việc có thể chuỗi nhà điều hành đặc biệt này, không cụ thể giải quyết vấn đề an toàn tôi mô tả ở trên (mặc dù nó chắc chắn không giải quyết nó). Ngoài ra, nó được đánh dấu là đã đóng và xem xét lại cho tiêu chuẩn tiếp theo. Như vậy, tôi nghĩ rằng tôi muốn hỏi ở đây:

Có lý do chính đáng nào khiến quá tải nêu trên trả về tham chiếu lvalue không?

+0

vì một lý do nào đó tất cả các MSVC tôi đã thấy dường như cho phép một liên kết giá trị với tham chiếu không phải const để trả về rvalue sẽ không thay đổi bất kỳ điều gì cho MSVS. –

Trả lời

15

Đó là lỗi và đó là lỗi của tôi, xin lỗi. LWG 1203 (cảm ơn vì đã tìm kiếm điều đó cho tôi! :-)) là ý kiến ​​hiện tại của tôi về bản sửa lỗi chính xác cho "rvalue-stream-inserter". Lưu ý rằng mặc dù bạn vẫn có thể bắt nó và thể gặp rắc rối:

auto&& s = (std::stringstream() << "hi there!\n"); 
std::cout << s.rdbuf(); // oops 

Mặc dù ít nhất là trong đoạn mã trên nó là rõ ràng hơn một chút (vì &&) rằng bạn đang làm một cái gì đó bạn không nên.

+2

Hm .. sau đó ..thậm chí không tốt hơn nếu không trả lại tham chiếu nào cả, nhưng chỉ là 'basic_ostream ' được chuyển vào? Điều đó sẽ vô hiệu hóa ràng buộc ref lvalue và cho phép các ngữ nghĩa thích hợp của phần mở rộng suốt đời thông qua 'auto &&' và 'auto const &', trong khi vẫn có thể kết nối toán tử đó như bạn đã đề xuất. – Xeo

+0

Điều đó sẽ an toàn hơn. Nhưng tôi không chắc rằng hiệu suất đạt được sẽ đáng giá. Mặc dù di chuyển một luồng tương đối rẻ, tôi không chắc nó đủ rẻ để thực hiện mọi hoạt động chuỗi. Nhưng nó là một cái gì đó để suy nghĩ thêm về ... –

+0

Tôi tin rằng tối ưu hóa nên đá ở đây, eliding gần như tất cả các di chuyển (mặc dù nó có thể là xấu để dựa vào đó). Tuy nhiên, tôi nhận thấy một nhược điểm nhỏ khác - các lớp dẫn xuất do người dùng định nghĩa 'std :: ostream' cũng sẽ cần phải di chuyển, và có thể có các lớp chứa bộ đệm có kích thước cố định sẽ mất thời gian O (N) để" di chuyển " . Một lần nữa, tối ưu hóa nhiều khả năng sẽ làm cho điều này trở thành no-op, nhưng nếu chúng không khởi động, nó sẽ nghiêm trọng hơn. – Xeo

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