はくさいのメモ帳

調べたことのメモをするだけです

恐るべしC++

知らぬ間にC++は進化していた。右辺値参照ってやつだ。
いや本当はちょっと名前くらいは知ってたけど、ふーんコピーしなくするのかふーんという感じで右から左に抜けていた。だってこんな難しそうなの使わないからいいやって思うじゃん?

嘘だけどw
せっかく実装されたのなら使わずにはいられない。しかし面倒そうなので一般に広まるまではかじるのを控えてただけ。ただ本当に内容を把握したのは今日が初めてでまだちゃんと理解できていない。
まずは今までもあった左辺値参照。

#include <iostream>
using namespace std;
int main(int arc, char* argv[]) {
    int i = 1;
    int& j = i;
    j = 2;
    cout << i << endl;
    return 0;
}

これ出力は2だよね。左辺値参照の実体は初期化時に決められたiだから、jを書き換えればiの中身が変わる。右辺値参照はその名前のとおり、右辺値で初期化される参照。

#include <iostream>
using namespace std;
int main(int arc, char* argv[]) {
    int&& i = 1;
    i = 2;
    cout << i << endl;
    return 0;
}

実際のところ右辺値なら何でもいいようで、これが怒られずに2が出力される。実体はリテラルの1のはずなのに書き換えられてしまうのだ。何コレ本当に参照なの?と疑いたくなる。では…とこうすると…。

#include <iostream>
using namespace std;
int main(int arc, char* argv[]) {
    int j = 1
    int&& i = j;
    i = 2;
    cout << j << endl;
    return 0;
}

エラーで怒られる。左辺値だから初期化できないとのこと。そんなの自動でキャストしろよと思うけど、どうやら文法上それを許すとオーバーロードの解決に支障が出るらしい。まあ素人目にも曖昧にはなるよね左辺値参照と右辺値参照のオーバーロードが。ではキャストしたらどうなるか?

#include <iostream>
using namespace std;
int main(int arc, char* argv[]) {
    int j = 1
    int&& i = static_cast<int&&>(j);
    i = 2;
    cout << j << endl;
    return 0;
}

これならコンパイルが通った。で、2が出力される!確かに参照なのだ。右辺値万歳!生存期間も書き換え可能なのかも知らない状態で堂々と使える恐ろしい参照万歳!

ちなみに、static_castでなくreinterpret_castにすると結果が変わるので面白い。

#include <iostream>
using namespace std;
int main(int arc, char* argv[]) {
    int j = 1
    int&& i = reinterpret_cast<int&&>(j);
    i = 2;
    cout << j << endl;
    return 0;
}

これの結果は1。実に面白い。