7

考虑以下代码:

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 而不是一个右值引用),但是如果有人编写上面的代码,我认为这是一个使用错误,因为代码看起来像是在自找麻烦。是否存在上述返回右值引用的运算符存在问题的“规范”真实世界示例?为什么我应该始终从运算符返回右值,有什么令人信服的理由?

4

2 回答 2

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 基于范围的 for 语句 [stmt.ranged]

1对于for形式的基于范围的语句

for (for-range-declaration:表达式)语句

range-init等价于用括号括起来的表达式

( expression )

对于形式的基于范围的for语句

for (for-range-declaration 大:括号初始化列表)语句

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返回的临时对象的生命周期,但不会延长 range-init 内嵌套临时对象的生命周期

于 2013-04-25T23:02:15.447 回答
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");工作。

于 2013-04-25T23:05:57.977 回答