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 -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
   }
}

range-initauto && __range = range-init;から返されたテンポラリの有効期間は延長されますが、 range-initにネストされたテンポラリの有効期間は延長されないことに注意してください。

于 2013-04-25T23:02:15.447 に答える