この記事は下記の人におすすめ
- &がむずかしいんだよー
- 仕様書を読みたいわけじゃないんだ
- 正確な認識じゃなくても,ざっくり使い分けがわかればとりあえず良し
- 結局プログラムの動きにはどう関わってくるの?
- 似ている書き方の機能の違いが一覧したい
- 左辺値(lvalue)はLv,右辺値(rvalue)はRvと省略してるかも。
- prvalue, xvalueは手に負えないので整理できてない。
- ついでにconstとも絡めて全体を見回したい。
勉強中(整理中)なので,間違ってたら教えてください!
ただ,趣旨として「雑に解釈できれば良い」と思っているので正確な表現ということにおいては見逃してほしいです。
変数宣言にて
宣言 | 値の渡し方例 | 値コピー処理 | 一言メモ |
---|---|---|---|
int a; | a=10; a=x; |
有り | |
int* a; | a=&x; | なし | ポインタ |
int& a = x; | a=x; | なし | 参照(左辺値参照)は既にある左辺値の別名をつける感じ |
int&& a; | a=10; | なし | 右辺値参照は一時オブジェクトにアドレスをつける感じ。aそのものはLvとなる。RvをLvにする役目? |
const int& a; | a=10; a=x; |
なし? | read only |
関数の引数として
|引数の型 |値の渡し方|値のコピー処理|取りうる値|一言メモ|
|---|---|---|---|---|---|
|f(int x)|値|あり|Lv, Rv両方|xは非破壊|
|f(int* x)|アドレス|なし?|Lvのアドレス|*xでアクセス|
|f(int& x)|アドレス?|なし?|Lvのみ|xでアクセス|
|f(int&& x)|アドレス?|なし?|Rvのみ|右辺値参照と表現されるが,正しくは転送参照, ユニヴァーサル参照らしい?|
|f(const int& x)|アドレス?|なし?|Lv,Rv両方|xはread only|
constもついでに説明すると
constのついた変数
変数にconst修飾がついている場合は「constおじさん」を読むといい。
表にすれば下記のようです。ダブルポインタのconstは鬼ですね。
const修飾の仕方 | 違い |
---|---|
const int x | xの値は変更できない(=不変,=immutable) |
int const x | 同上 |
const int* x | xの値は変更可能。*xは変更不可能。ポインタは書き換え可能 |
int* const x | xの値は変更不可能。*xは変更可能。ポインタ先の変数書き換え可能 |
const int* const x | xの値も*xの値も変更不可能。 |
const int** x | もうめんどい。constおじさん見て。 |
int* const* x | もうめんどい。constおじさん見て。 |
int** const x | もうめんどい。constおじさん見て。 |
int const** const x | もうめんどい。constおじさん見て。 |
int* const* const x | もうめんどい。constおじさん見て。 |
int const* const* x | もうめんどい。constおじさん見て。 |
const int** const x | もうめんどい。constおじさん見て。 |
const int* const* x | もうめんどい。constおじさん見て。 |
const int* const* const x | もうめんどい。constおじさん見て。 |
&が関数を修飾して,constとも関連して
&とconstがつくメンバ関数の呼び出し方の違いは下記のようです。
メンバ関数の型 | 違い |
---|---|
f(x) & | *thisがlvalueの時呼ばれる |
f(x) && | *thisがrvalueの時呼ばれる |
f(x) const & | *thisが const lvalueの時呼ばれる |
f(x) const && | *thisが const rvalueの時呼ばれる |
f(x) | 上記の対応がないときに呼ばれる(要検証) |
右辺値?左辺値?
「lvalueは名前付きのオブジェクト、rvalueは一時的に生成される無名のオブジェクト」と表現されることがある。でも調べてみるとやっぱりいろいろ不具合があるっぽい。例えば下記のパタンが上記解釈では例外になる。
- ヒープに確保したオブジェクトは名前がないlvalue
- 配列の要素も名前のないlvalue
自分は**「lvalueはアドレスをコンパイラが意識しているがrvalueはアドレスをコンパイラが気にしていない。」**という解釈で理解しようと思う。