Custom stream class used as temporary

102 Views Asked by At

I want to code another stream class. Done it before like this:

class MyStream
{
   // ...
};

template <typename T>
MyStream& operator <<(MyStream& s, const T& t) noexcept
{
   std::cout << t;
   return s;
}

void f()
{
   MyStream s;
   s << 666;
}

This time I need to make it work with temporaries as well:

void f()
{
   MyStream() << 666;

   MyStream s;
   s << 777;
}

I understood that this can be solved using an rvalue reference:

template <typename T>
MyStream& operator <<(MyStream&& s, const T& t) noexcept
{
   std::cout << t;
   return s;
}

However I do not understand the implications of doing so.

Should I implement a conventional lvalue reference operator as well? Is there anything that could go wrong? Is it ok to convert a rvalue reference into a lvalue reference like this?

1

There are 1 best solutions below

10
Oliv On

Never turn an rvalue into an lvalue. This is one the most common causes of dangling reference. You could return an rvalue reference but that is already a mistake:

template <typename T>
MyStream&& operator <<(MyStream&& s, const T& t) noexcept
{
   std::cout << t;
   return std::move(s);
}

void foo(){
    auto && o = Mystream{} << 12;
    o << "x" ; //undefined behavior
    }

The moral is never return an rvalue reference and never turn an rvalue into an lvalue. The corollary is always ref qualify assignment operators and pre-increment/pre-decrement operators. Those who are not able to follow this simple discipline should switch to Rust as it does not offer the opportunity to such mistakes.