C++ 11 rvalue とは何か

はじめに

これは気にする必要のないことなのでこれまで意図的に説明しなかったことなのですが、rvalue とは何者なのかということについて気になる人も多いようです

rvalue参照についてはこれまで何度か説明をしてきましたが、そこでは「rvalue参照の rvalue とは一時オブジェクトである」と言ってきました

「rvalue とは」ではなく「rvalue参照の rvalue とは」です
rvalue参照の文脈で rvalue と言えばそれは必ず一時オブジェクトのことです
しかし rvalue参照と関係の無い文脈での rvalue は必ずしも一時オブジェクトであるとは限りません
では rvalue とは何者なのでしょうか

ここでは rvalue とは何者なのか
なぜそれを知る必要がないのかを説明しましょう

標準では

標準では次のように言っています

N3797
3 Basic concepts
3.10 Lvalues and rvalues

1 Expressions are categorized according to the taxonomy in Figure 1.
  - An xvalue (an "eXpiring" value) also refers to an object, usually near the end of its lifetime (so that its resources may be moved, for example).
    An xvalue is the result of certain kinds of expressions involving rvalue references (8.3.2).
    [ Example:
      The result of calling a function whose return type is an rvalue reference is an xvalue.
    -end example ]
  - An rvalue (so called, historically, because rvalues could appear on the right-hand side of an assignment expression) is an xvalue, a temporary object (12.2) or subobject thereof, or a value that is not associated with an object.
  - A prvalue ("pure" rvalue) is an rvalue that is not an xvalue.
    [ Example:
      The result of calling a function whose return type is not a reference is a prvalue.
      The value of a literal such as 12, 7.3e5, or true is also a prvalue.
    -end example ]

Figure 1.

別にこんな用語を覚える必要はありませんが、
rvalue には xvalue と prvalue というものがあり、
xvalue というのは寿命の尽きかけているオブジェクトである。また明示的に rvalue参照にキャストしているものも同様である。
prvalue というのは一時オブジェクトや参照でない関数の戻り値や数値リテラルなどの xvalue 以外の rvalue のことである。
と言っています

xvalue の発見

今までの C/C++ では expression(式) は名前のある lvalue と 名前のない rvalue に大別されると素朴に信じられてきました
f:id:prettysoft:20200601133253p:plain

しかしそれを詳細に検討してみると、実は名前のある lvalue であってももはや誰も触らなくなって破棄を待つだけになった lvalue は rvalue であるとみなせるのではないかということが認識されるようになりました
ここでこの rvalue としてみなすことのできる lvalue を xvalue と名付けてみます
f:id:prettysoft:20200601133256p:plain

一方大多数の rvalue とみなすことのできない lvalue もあります
今まではこの rvalue と見なすことのできない真の lvalue と xvalue を区別せずどちらも lvalue と呼んできましたが、これからは xvalue でない真の lvalue だけを lvalue と呼ぼうということになりました
今までのように真の lvalue と xvalue を区別しない場合の名前は glvalue と呼ぶことになりました
f:id:prettysoft:20200601133259p:plain

ところで xvalue は rvalue と見なすことができるものですから、今や rvalue と言えば名前のない真の rvalue と、それに加えて xvalue のことも含むようになりました
今まで rvalue と呼ばれていた名前のない真の rvalue は prvalue と呼ぶことになりました
f:id:prettysoft:20200601133301p:plain

今や C++ では expression(式)は、名前のある glvalue と rvalue に大別されます
f:id:prettysoft:20151102123748g:plain

rvalue とは何者でしょうか

rvalue とは何者か

一時オブジェクトは rvalue 参照で言うところの rvalue です
また xvalue というのも rvalue参照で言うところの rvalue と同等のものです
rvalue参照の文脈での rvalue 以外の rvalue というと残っているのは数値リテラルくらいのものですね
そう。それだけなのです

そう言われても何のことか分からないという人はアセンブラの世界が見えていないのです
これが知らなくていいということの理由です

アセンブラの世界が見えていれば簡単なことなのです

アセンブラの世界での rvalue

イミディエイトの入っているところはどこでしょうか
長ければ定数用のメモリに置いてあるでしょうが、短ければそれは命令コードの中ですね

関数の戻り値を置くところはどこでしょう
それはレジスタだったりスタックだったりするでしょう

定数用のメモリやスタックにはアドレスはありますが、それがどこにあるのかはコンパイラが知っていればいいことなので、C++ の世界に見えるラベルは付いていません
レジスタにも命令コードの中のイミディエイトにもラベルは付いていません
関数に引数を渡すときなど暗黙に型変換をして生成するオブジェクトにいちいちラベルをつけるでしょうか
rvalue に名前が無いというのはそういうことです

C++ の世界しか見えない人が rvalue が何者かということをはっきりイメージすることができないというのは当たり前なのです
それは C++ の世界からは見えないものなのです
見えないけれどもそこにあるもの
それに rvalue という名前を付けたのです

だから一時オブジェクト以外の rvalue については気にしなくて構いません
アセンブラを覚えればその内わかるようになります

C++ の世界での rvalue

しかし一時オブジェクトは C++ の世界に実体を持って現れた rvalue です
これは C++ 11 の時代になって rvalue参照が導入されたことで一層重要なものになりました
一時オブジェクトについてはよく理解するようにしましょう
一時オブジェクト以外の rvalue については気にする必要はありません

結局

xvalue は寿命が尽きようとしているオブジェクトやプログラマがそのように指定したオブジェクトです
xvalue は元々は lvalue ですがもはや中身を壊してしまっても誰にも迷惑をかけないものだという点で一時オブジェクトと共通しています
この性質が rvalue参照で参照するのに適しています

prvalue である数値リテラルC++ の世界から見ると抽象的存在なのでそのままでは参照することができませんが、一時オブジェクトを生成することによって C++ の世界に実体を持って現れます
prvalue である参照でない関数の戻り値も同様です
prvalue である一時オブジェクトは rvalue参照で参照することができます

rvalue に関するすべては一時オブジェクトと rvalue参照に繋がります

因果が逆ですが、rvalue参照で参照することのできるものが rvalue なのです
C++ の世界で rvalue と言ったら rvalue参照の文脈での rvalue のことだと思っていて構いません
rvalue参照の文脈での rvalue と言ったら一時オブジェクトのことだと思っていて構いません