I was interested in this, so I knocked up a little test program:
#include <memory>
#include <iostream>
struct Bar
{
// Return by reference
Bar& doThings() & { return *this; }
// Return by rvalue reference
Bar&& doThings() && { std::cout << "in Bar&& doThings, this=" << (void *) this << "\n"; return std::move (*this); }
~Bar () { std::cout << "Bar destroyed at " << (void *) this << "\n"; }
int first;
std::unique_ptr<int> m_content; // Make Bar a non-copyable type
};
int main ()
{
std::cout << std::hex;
Bar bar;
std::cout << "bar is at " << &bar << "\n";
Bar& bar_ref = bar.doThings ();
std::cout << "bar_ref refers to " << &bar_ref.first << "\n\n";
Bar&& bar_rvalue_ref = Bar ().doThings ();
std::cout << "bar_rvalue_ref refers to " << &bar_rvalue_ref.first << "\n\n";
}
Output:
bar is at 0x7ffdc10846f0
bar_ref refers to 0x7ffdc10846f0
in Bar&& doThings, this=0x7ffdc1084700
Bar destroyed at 0x7ffdc1084700
bar_rvalue_ref refers to 0x7ffdc1084700
Bar destroyed at 0x7ffdc10846f0
So this tell us that neither form of doThings()
creates a temporary. You can also verify this at Godbolt.
So, looking at the implementation of Bar
as written, where does this leave us? Well, I personally can't see any purpose in Bar&& doThings()
at all because:
- AFAICT, you can only call it on a newly constructed object so there seems little point in it anyway.
- Because it moves from
*this
, it eats, in principle, that newly constructed object so the reference returned (which still refers to it) is not to be relied on.
- The temporary created in step 1 has an infinitessimal lifetime, as @xskxzr has already pointed out.
Whereas, Bar& doThings()
works just fine (and, returns, in effect, a pointer to the object itself, so no copying or temporaries will ever be involved).
I'm sure I've missed something important so I'd love to hear people's reactions to this. Surely there is some purpose in returning by rvalue reference, perhaps in more complicated scenarios. Thanks.
Live demo