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の挙動は
にまとめる。