らんだむな記憶

blogというものを体験してみようか!的なー

左辺値と右辺値

みんなlvalueとrvalueを難しく考えすぎちゃいないかい? - Qiita というのがある。

lvalue := 名前のあるオブジェクト
rvalue := 名前のないオブジェクト

正しくないと指摘はあるが分かりやすい。

右辺値、左辺値などの細かい定義 - Qiita だと急に小難しくなる。結局どう考えるのが良いのだろう?ローカルオブジェクトを返す - らんだむな記憶 は “右辺値” の話だと理解している。

ISO/IEC JTC1/SC22/WG21 - The C++ Standards Committee - ISOCPP この辺から n4140.pdf (C++14 draft) をとってこよう。p.78 にありがたい解説がある。

3.10 左辺値 (lvalues) と右辺値 (rvalues)

1 表現は、Figure 1 の分類法に従って分類される。

f:id:derwind:20210706222810p:plain

(1.1) lvalue(左辺値)(歴史的には、lvalue が代入式の左辺に現れることがあったのでそう呼ばれていた)は、関数やオブジェクトを指定する。[例 E をポインタ型の式とすると,*E は E が指すオブジェクトや関数を指す lvalue 式である。他の例としては、戻り値の参照型が lvalue である関数を呼び出した結果は lvalue である。— 例おわり]
(1.2) また、xvalue(「死にかけ」の値)は、通常、(例えば、そのリソースをムーブできることができるように)寿命が尽きる寸前のオブジェクトを指す。xvalue は、rvalue の参照を含むある種の式の結果である (8.3.2)。[例 戻り値の型がオブジェクト型への rvalue 参照である関数を呼び出した結果が xvalue である (5.2.2)。— 例おわり]
(1.3) glvalue(「一般化された」左辺値)とは、lvalue または xvalue のことである。
(1.4) rvalue(右辺値)(歴史的には、rvalue が代入式の右辺に現れることがあったため、このように呼ばれている)は、xvalue、一時的なオブジェクト (12.2) またはそのサブオブジェクト、またはオブジェクトに関連付けられていない値である。
(1.5) prvalue(「純粋」右辺値)とは、xvalue ではない rvalue のことである。[例 戻り値の型が参照ではない関数を呼び出した結果は、prvalue である。また、12、7.3e5、true などのリテラルの値も prvalue である。— 例おわり]

すべての式は、この分類法の基本的な分類である lvalue、xvalue、prvalue のいずれかに正確に属する。式のこの特性は、その値のカテゴリと呼ばれる。[注: 第 5 節の各組み込み演算子の説明では、それがもたらす値のカテゴリと、それが期待するオペランドの値のカテゴリを示している。例えば、組み込みの代入演算子は、左のオペランドが lvalue で、右のオペランドが prvalue であることを想定し、結果として lvalue を得る。ユーザー定義の演算子は関数であり、期待される値のカテゴリと結果は、パラメータと戻り値の型によって決定される。— 注おわり]

2 prvalue が期待される文脈で glvalue が出てきた場合、glvalue は prvalue に変換される。4.1、4.2、および 4.3 を参照のこと。[注: rvalue の参照を lvalue にバインドする試みは、そのような文脈ではない。— 注おわり]

3 8.5.3 の参照の初期化と 12.2 の一時変数の議論は、他の重要な文脈における lvalues と rvalues の動作を示している。

4 他に指示がない限り (5.2.2)、prvalues は常に完全な型か void 型を持る。これらの型に加えて、glvalues も不完全な型を持つことができる。[ 注: クラスや配列の prvalues は、const 或は volatile で修飾された型を持つことができる。第 5 節を参照のこと。— 注おわり]

5 オブジェクトを変更するためには、オブジェクトに対する lvalue が必要であるが、ある状況下では、クラス型の rvalue を使って参照先を変更することもできる。[例: オブジェクトに対して呼び出されたメンバ関数 (9.3) は、オブジェクトを変更することができる。— 例おわり]

6 関数は修正できないが、関数へのポインタは修正可能である。

7 不完全な型へのポインタは修正可能である。指し示されていた型が完全になったプログラムのある時点で、そのポインタが指すオブジェクトも変更できる。

8 const 修飾された式の参照先は、(その式を通して)変更してはならない。ただし、クラス型であり、変更可能なコンポーネントを持つ場合は、そのコンポーネントを変更することができる (7.1.6.1)。

9 ある式が、その式が参照しているオブジェクトを修正するために使用できる場合、その式は修正可能と呼ばれる。オブジェクトを、変更できない lvalue や rvalue の式で変更しようとするプログラムは、不正な形式となる。

10 プログラムが以下のタイプ以外の glvalue を使ってオブジェクトの格納値にアクセスしようとした場合、その動作は未定義である:

(10.1) オブジェクトの動的な型、
(10.2) オブジェクトの動的な型の const 或は volatile で修飾されたバージョン、
(10.3) オブジェクトの動的な型に似た型(4.4 で定義)、
(10.4) オブジェクトの動的な型に対応する符号ありまたは符号なしの型、
(10.5) オブジェクトの動的な型の const 或は volatile で修飾されたバージョンに対応する、符号ありまたは符号なしの型、
(10.6) その要素または非静的データメンバーの中に前述のタイプの 1 つを含む集成体または共用体型(再帰的に、サブ集成体または入子の共用体の要素または非静的データメンバーを含む)、
(10.7) オブジェクトの動的な型の(場合によっては const 或は volatile で修飾された)基底クラス型である型、
(10.8) char または unsigned char 型。

うん・・・やっぱりほとんど分からないね。「オブジェクトの動的な型」というのは、継承関係にあるクラス同士の基底クラスのポインタをでリファレンスした時に出てくる派生クラスの型のようなものみたいだ。何にしても、“左辺値” だとか “右辺値” だとかいうものは歴史的な経緯でそういう名前になっているものであって、見た目上のそれというわけではないようだ。ということがあまり細かく書いてある本を見たことがないので、いきなり「左辺値」とか言われると「代入式の左辺に置ける対象??」と思うのである・・・。