请考虑以下代码:
struct MyString
{
// some ctors
MyString& operator+=( const MyString& other ); // implemented correctly
};
MyString operator+( const MyString& lhs, const MyString& rhs )
{
MyString nrv( lhs );
nrv += rhs;
return nrv;
}
MyString&& operator+( MyString&& lhs, const MyString& rhs )
{
lhs += rhs;
return std::move( lhs ); // return the rvalue reference we received as a parameter!
}
这适用于以下用例
MyString a, b, c; // initialized properly
MyString result = a + b + c;
但它为
创造了一个悬垂的参考const MyString& result = a + b + c;
现在,我理解为什么会这样,以及如何修复它(返回一个ravlue而不是rvalue引用)但我认为如果有人写上面的代码看起来像是在寻找麻烦,这是一个使用错误。是否有任何“规范”的现实示例,其中上述运算符返回右值引用是一个问题?为什么我总是应该从运算符返回一个rvalue有什么令人信服的理由?
答案 0 :(得分:9)
您要查找的示例是基于范围的for
声明:
MyString a, b, c;
for( MyCharacter mc : a + b + c ) { ... }
在这种情况下,a + b + c
的结果绑定到引用,但嵌套的临时(由a + b
生成并作为(a + b) + c
的右值引用返回)在范围之前被销毁基于for循环执行。
标准在
中定义了基于范围的for循环6.5.4基于范围的语句[stmt.ranged]
1 对于表单
的基于范围的for
语句
for (
换范围声明:
表达)
语句让 range-init 等同于括号所包围的表达式
( expression )
以及表单
的基于范围的for
语句
for (
换范围声明:
支撑-INIT列表)
语句让 range-init 等同于 braced-init-list 。在每种情况下,基于范围的
for
语句等同于{ auto && __range = range-init; for ( auto __begin = begin-expr, __end = end-expr; __begin != __end; ++__begin ) { for-range-declaration = *__begin; statement } }
请注意,auto && __range = range-init;
会延长从 range-init 返回的临时值的生命周期,但它不会延长< 内嵌套临时值的生命周期EM>范围-INIT
答案 1 :(得分:5)
您应该信任字符串自己的移动构造函数,而不是要求麻烦:
MyString operator+(MyString lhs, MyString rhs)
{
lhs += std::move(rhs);
return std::move(lhs);
}
现在,MyString x = a + b;
和MyString y = MyString("a") + MyString("b");
都能有效运作。