2014年9月7日日曜日

rvalueとlvalueって何?rvalue参照って?

これまで、rvalue参照は壊していいと説明してきました。
しかし、何故でしょう?

というわけで少し解説。
辞典などを引くと、rvalueは右辺値、lvalueは左辺値と出てきます。
分かりやすい言葉で、分かったような気になりますが、実は何も分からない名前ですw

コンパイラの授業なんかを取ると、
lvalueはメモリ位置(アドレス)
rvalueはlvalueのメモリ位置に記録されている値
などと説明されます。

感のいい人だと、アドレスと値のことかな?なんて分かったかもしれませんね。

lvalueとrvalueは、例えば以下のCの式の左辺値と右辺値です。
a = a * 12;
これをコンパイラの中間表現の一種、three-address codeで書くと、
t1 = &a         // aのアドレス取得
t2 = *t1         // aの値取得
t3 = t2 * 12   // aの値×12
*t1 = t3         // aの値×12をaのアドレスに書き戻す
なんてなるわけですが、Cの式の「代入」という処理の左辺と右辺は、
この最後の行の左辺と右辺のことなわけです。

つまり、元々、lvalueはメモリ上のアドレスで、
rvalueはレジスタ上の値のことでした。


lvalueはメモリ上のアドレス、つまりその中身は永続的なので壊してはいけません。
rvalueはレジスタ上の値、テンポラリな物なので壊しても問題ありません。
これが、rvalueやrvalue参照を壊していいという考え方の背景です。

Cは高級言語なので、変数名さえ付いていれば代入できてしまいます。
そこらへんから、元々の意味と乖離したんでしょうね。

例えば、“a = b;”のaはaがレジスタ上にとられててもlvalueと呼びますし、
“int fun(int a)”なんて関数のaを指してrvalueでといった呼び方もします。
“int fun(const int a)”のように、constが付くと破壊できなくなるため、
lvalueになったなどという場合もあります。

C++では、もう、破壊可能な物がrvalue、破壊してはいけない物がlvalueと
考えたほうが良さそうなありさまです。

さて、いつの間にレジスタ上の値だったrvalueが、
参照なんていうメモリ上のアドレスを得ることができるようになったのでしょうか。

これは、C++で導入された参照が関係してるんではないでしょうか。
参照できるのは、アドレスを持つlvalueのみです。しかし、
setName("hello")などとやった場合の()の中身はrvalueですので
参照渡しが使えません。それが都合が悪かったので、const付き参照のみ、
rvalueを参照しても良いと例外を作り、そこからrvalueのアドレスが
とれるようになったのだと思います。

今回C++11で、rvalue参照を作ったことで、
ここらへんのネジレが解消すればいいですね。
とはいえ、元々メモリ位置とは関係なかったrvalueに、
アドレスを与えて参照するのをどんな場合にでも許すとか、
ますます元の意味からかけ離れていってる気もしますが。
まあ、高速化ジャンキーの考えることですから、しょうがないですねw

Happy Hacking!

0 件のコメント:

コメントを投稿