杉山利幸の公開日誌 2026年7月分

2026/07/04 T& と T&& の 違い


2026/07/04 T& と T&& の 違い

"&&"は後置詞の一つと考えると前回は述べたが、ならばその性格を明らかにしよう。
int val =...;
int& val =...;
int&& val =...;
の3つを比較しよう。

色々コンパイルエラーが出るかどうか試してみたところ

int val =...;なんでもOK

int& val =...;定数NG、加減剰余NG、変数は a->b.c[i] までOK
別名を付け一心同体になると考えると納得できる。
int がクラスになる時も試したが val はコンストラクターもデストラクターも動かない。

int&& val =...;定数OK、1変数NG、式OK
要するに「int& val」でNGなものが全部OKという事になる。

今ここでわかってしまったことがある
int& val = 左辺値、int&& val = 右辺値
という事だ。
世の中には 左辺値でも右辺値でもない式があるらしいが無視しよう。

一応サンプルプログラムを示す。
//
//	T& の例
	struct struct0{ int i; char c[10];};
	struct struct1{ struct0 str0; int j;} str1;
	struct1* pstr1 = &str1;
	char& cc = pstr1->str0.c[3];//cc は pstr1->str0.c[3] の別名、pstr1->str0.c[3] が未定義でも可
	cc = 'g';
	Debug(cc, pstr1->str0.c[3]);//'g', 'g' と出力
	pstr1->str0.c[3] = 'k';
	Debug(cc, pstr1->str0.c[3]);//'k', 'k' と出力
	//結論「int& x = y;」は y の別名を x とし一心同体になる
//
//	T&& の例
	int x = 70;
	int&& b = x + 20;
	Debug(b, x);//90, 70 と出力
	x = 60;
	Debug(b, x, b + x);//90, 60, 150 と出力
	b = 10;//int&& 宣言した変数も int と同じように普通に使える
	Debug(b, x);//10, 60 と出力
	//結論 x と b の間に関係はない

この中でDebug(...)というのはここでいう画面表示用関数である。

以前デストラクターは';'と'}'の所で暗黙的に働くと述べたが、
結論として
int val = x + 20;//x + 20 を計算しそれを val にコピーし、計算結果は';'の所でデストラクトする
int& val = a->b.c[i];//変数 a->b.c[i] の別名として val を定義し一心同体となる。
   val はコンストラクターもデストラクターも動かない
int&& val = x + 20;//x + 20 を計算しそれを val とし、';'の所では計算結果をデストラクトしない

int をクラス T にして試してみると

T& は上記と同じで別名になり、コンストラクターもデストラクターも動かない。

T val = 左辺値 の場合、コピーコンストラクターが動く。
T val = 右辺値 の場合、
ムーブコンストラクターがないとコピーコンストラクターが動く、
ムーブコンストラクターがあるとムーブコンストラクターが動く。

T&& val = 左辺値 の場合、コンパイルエラー
T&& val = 右辺値 の場合、
ムーブコンストラクターがないとコピーコンストラクターが動く、
ムーブコンストラクターがあるとムーブコンストラクターが動く。

ということになった。

クラスであれば、チャックライトを入れて色々試せるが
int のがどうなっているかは試せません。
ちょっと想像も含めています。
しかしムーブコンストラクターがあったとしても
sizeof(int) = 4、sizeof(int*) = 4
なので処理を早くする効果はそんなにないかも。


2026年6月分

戻る