C++におけるlvalue(左辺値)、rvalue(右辺値)

https://cpplover.blogspot.com/2009/11/rvalue-reference_23.html

上記をよく見て勉強しよう。

キーワードを抜粋。

  • lvalueとは、明示的に実体のある、名前付きのオブジェクトであり、rvalueとは、一時的に生成される無名のオブジェクトである。
struct X{};
int f() { return 0; }

int main()
{
  int i = 0;

  i;   // lvalue
  0;   // rvalue

  X x;

  x;   // lvalue
  X();  // rvalue

  f();  // rvalue
}
  • lvalueはrvalueに変換できるが、その逆は不可。

なお、関数の仮引数はlvalueなので、const参照でない限りrvalueは受け取れない。(若干不安。要確認)

lvalue reference

C++98のreferenceは、C++11においては、lvalue referenceと呼ばれる。

struct X{ } ;

void f( X & ) { }
void g( X const & ) { }

int main()
{
  X x;

  f( x );  // 1. OK
  f( X() ); // 2. Error

  g( X() ); // 3. OK
}

rvalue reference

rvalue referenceとは、rvalueに対する参照。アンパサンドを二つ使って表現する。

struct X{ };

int main()
{
  X x;

  // lvalue reference
  X & lr1 = x;    // 1. OK
  X & lr2 = X();   // 2. Error

  // rvalue reference
  X && rr1 = x;   // 3. Error
  X && rr2 = X();  // 4. OK
}

サンプル:右辺値参照の仮引数を受け取る関数の呼び出し

#include <iostream>
#include <vector>

struct X{ };

void funcB(X&& rr){ 
  std::vector<X> a;
  a.emplace_back(rr); // OK Xのコピーコンストラクタが呼ばれる
  a.emplace_back(std::move(rr)); // OK ただし、Xのムーブコンストラクタが呼ばれる
  return;
} 
void funcA(X&& rr){
  //funcB(rr); // Error ビルドが通らない
 funcB(std::move(rr)); // OK
}

int main()
{
  X x;

    funcA(x); // Error ビルドが通らない
    funcA(std::move(x)); // OK
}

結論をまとめると、右辺値参照を受け取れる関数を呼び出す際は、std::move()が必要。
ただし、std::vectorのemplace_backはstd::move()で渡さない方がいいかも?
ということ。
emplace_backは複数の仮引数が定義されているので、コピーコンストラクタかムーブコンストラクタが呼ばれるという挙動の違いにつながる。

emplace_backの挙動は

std::vectorへのpush_back(T)、push_back(std::move(T))、emplace_back(T)、emplace_back(std::move(T))の違いについて考察


にまとめる。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です