On 15/11/2017 07:16, Daniel Frey wrote:
Before looking at those cases, consider a commutative operator+ (abbreviated version):
T operator+( const T& lhs, const T& rhs ) { T nrv( lhs ); nrv += rhs; return nrv; } // v1 T&& operator+( T&& lhs, const T& rhs ) { lhs += rhs; return std::move( lhs ); } // v2 T&& operator+( const T& lhs, T&& rhs ) { rhs += lhs; return std::move( rhs ); } // v3, remember: we assume a commutative + T&& operator+( T&& lhs, T&& rhs ) { lhs += rhs; return std::move( lhs ); } // v4
Given that NRVO is mandatory now, isn't it just as efficient and more correct to declare these as: T operator+( const T& lhs, const T& rhs ) { T nrv( lhs ); nrv += rhs; return nrv; } // v1 T operator+( T&& lhs, const T& rhs ) { lhs += rhs; return lhs; } // v2 T operator+( const T& lhs, T&& rhs ) { rhs += lhs; return rhs; } // v3, remember: we assume a commutative + T operator+( T&& lhs, T&& rhs ) { lhs += rhs; return lhs; } // v4 (You could save a little typing by using "return lhs += rhs;" but that's probably not a good idea as you're left to the whims of compiler inlining whether it triggers some kind of RVO or not.) Unless I'm missing something?
a) Explicitly binding to a reference "to prolong the lifetime of the temporary".
This happens if you write
const T& t = t1 + ( t2 + t3 ) + t4;
As the last operator+ return an rvalue reference instead of an rvalue, the "const T& t =" does not bind to a temporary. The intermediate temporary created by (v2+v3) is destroyed at the end of the expression, hence t is now a dangling reference. Oops.
The above would fix this, and your other case.