7

右辺値の参照を理解していると思ったとき、この問題に遭遇しました。コードはおそらく不必要に長くなりますが、考え方は非常に単純です。main() 関数と returnRValueRef() 関数があります。

#include <iostream>

#define NV(x) "[" << #x << "=" << (x) << "]"
#define log(x) cout << __FILE__ << ":" << __LINE__ << " " << x << endl

using namespace std;

class AClass {
 public:
  int a_;

  AClass() : a_(0) {
    log("inside default constructor");
  }
  AClass(int aa) : a_(aa) {
    log("inside constructor");
  }
  int getInt() const {
    return a_;
  }
  void setInt(int a) {
    a_ = a;
  }

  AClass(AClass const & other) : a_(other.a_) {
    log("inside copy constructor");
  }

  AClass & operator=(AClass const & rhs) {
    log("inside assignment operator" << "left value" << NV(a_) << "right value" << NV(rhs.a_));
    a_ = rhs.a_;
    return *this;
  }

  AClass & operator=(AClass && rhs) {
    log("inside assignment operator (rvalue ref)" << "left" << NV(a_) << "right" << NV(rhs.a_));
    a_ = rhs.a_;
    return *this;
  }
};

AClass && returnRValueRef() {
  AClass a1(4);
  return move(a1);
}

int main() {
  AClass a;
  a = returnRValueRef();
}

さて、このコードは、最初に「デフォルト コンストラクター内」(a の場合)、次に「コンストラクター内」(a1 の場合)、そして rhs.a_ = 4 の代入演算子メッセージを出力することを期待します。しかし、出力は

testcpp/return_rvalue_ref.cpp:14 inside default constructor
testcpp/return_rvalue_ref.cpp:17 inside constructor
testcpp/return_rvalue_ref.cpp:39 inside assignment operator (rvalue ref)left[a_=0]right[rhs.a_=0]

right[rhs.a_=0]出力の最後の行が代わりに出力される理由を誰かが説明できますかright[rhs.a_=4]? move() は、内容を変更せずに左辺値を右辺値にするだけだと思いました。しかし、私は明らかに何かが欠けています。

どうもありがとうございました。:-)

編集:何が起こっているのか知っていると思います。a1関数内のデストラクタreturnRValueRef()がスコープ外に出たときに呼び出されている可能性があります (右辺値に変換されている場合でもa1)。それが起こっているかどうかはわかりませんが、もっともらしいようです。

4

1 に答える 1

18

右辺値参照は依然として参照です。あなたの場合、破壊されたローカル変数を参照しています。したがって、メンバーへのアクセスは未定義の動作です。あなたがしたいことは、オブジェクトを返すことです:

AClass returnRValueRef() {
  AClass a1(4);
  return move(a1);
}

ただし、移動はローカル変数で自動的に行われるため、実際にはこれを行うだけで済みます。

AClass returnRValueRef() {
  AClass a1(4);
  return a1;
}
于 2013-05-04T06:26:24.733 に答える