C++0x の右辺値参照がこんなに難しいわけがない。

C++0xのアレです。
これに関してはさんざん解説がされているとは思いますが、自分がイマイチ理解していなかったのでまとめてみました。
概念や細かい仕様なんかは書いてないのでありからず…。
あとテスト用のコンパイラは、gcc-4.5.0 です。

☆参照渡し

C++ では、型名に & を付けることでオブジェクトのアドレスを受け取り、値の参照を行うことが出来ます。

int n = 10;
int& ref = n;   // int* ref = &n; を行っているイメージ
ref = 3;        // ref は n を指しているので、代入すれば n も変わる


ここで重要なのは、参照渡しは値のコピーを行わない事です。
まぁこれに関しては、ポインタ渡しと同じですね。
関数の引数を参照で受け取るのは、無駄なコピーを行わない為です。

void hoge(std::string& str){}

std::string str("hogehoge");
hoge(str);        // 関数に渡す際に std::string のコピーは行われない


しかし、参照渡しは次のような一時的なオブジェクトを受け取ることは出来ません。

int& n = 10;    // int* n = &(10); を行っているイメージ

void hoge(std::string& str){}
hoge(std::string("hogehoge"));    // 関数に渡すことも出来ない


このような場合に右辺値参照を使用します。

☆右辺値参照

型名に && を付ける事で、右辺値参照でオブジェクトを受け取ることが出来ます。
これで無駄なコピーも行われず、値を受け取ることが出来ます。

int&& n = 10;

// 関数でも受け取ることが出来る
void hoge(std::string&& str){}
hoge(std::string("hogehoge"));


また、参照渡しとは逆に一時オブジェクト以外は受け取ることが出来ないので次のコードはエラーになります。

int n = 10;
int&& rvalue = n;    // 一時オブジェクト以外は受け取れない


ただし、これは、明示的にキャストを行うことで回避することが出来ます。

int n = 10;
int&& rvalue = static_cast<int&&>(n);
//int&& rvalue = std::move(n);         // こう書くことも出来る

☆関数の受け取り方の例

struct X{};

void func(X&){
    std::cout << "lvalue" << std::endl;
}
void func(X&&){
    std::cout << "rvalue" << std::endl;
}

X hoge(){
    return X();
}

X x;
func(x);                        // lvalue
func( X() );                    // rvalue
func( hoge() );                 // rvalue
func( static_cast<X&&>(x) );    // rvalue


この様に一時オブジェクトである場合と、そうでない場合で処理を切り分けることが出来ます。

☆まとめ

簡単にまとめると、右辺値参照とは、一時オブジェクトを受け取る参照渡しです。
いい方を変えれば、右辺値参照は一時オブジェクトであることを保証する、といってもいいかも知れません。
ムーブコンストラクタなどは、あくまでも右辺値参照を使ったテクニックの1つに過ぎません。
右辺参照値といわれるものの動きに関してはこれだけです。


と、まぁ理解の仕方に齟齬があるかも知れませんが、だいたいこんな感じだと思います。
右辺参照値だけに関していえば、単なるバズワードですね。
もっと詳しい仕様が知りたい方は、下記のサイトを参照してみてください。
あくまでも自分の解釈なので間違っていたらスミマセン……。


[参照]
http://cpplover.blogspot.com/2009/11/rvalue-reference_23.html