参照とポインタの機能面の違いというのは良く知られているかと思いますが,コード生成の違いに関しては結構知らない方が多いのかもと思い解説します。

記事が大変長くなってしまいましたが, 個人的には参照は非常に面白い物だと思っていましてそれが伝わればと思います。もし何か間違いがあれば誰か教えて下さい。

まず, 参照とはつまりエイリアス(別名)だというのは良いかと思いますが,それをどう実現するかに関して規格は一切言及していないんですね。どうやるかはコンパイラの自由です。

具体的にどういう実現方法があるかというと, unionやハードウェア固有の機能の利用(特殊なメモリとか)もありえますが,現実的には

ポインタ

名前置換 (分かり易く言うと #define x y みたいなただの置換)

がほとんどだと思います。

C++の参照は再代入不可, アドレス取得不可等の制約があるため簡単な解析で後者にも使えるというのがポイントで, Javaなどの参照とは異なっています。

そして, コンパイラはポインタなんて極力使いたくないので, 可能な場合は置換で参照を処理します。

では, どういう場合にポインタを使用するかというと他の関数の引数として渡す場合等, そうせざるを得ない場合です。例えば

void pair_swap(std::pair< int , int > &p) { int t = p.first; p.first = p.second; p.second = t; }

と

void pair_swap(std::pair< int , int > *p) { int t = p->first; p->first = p->second; p->second = t; }

は通常はほぼ同じアセンブリになると思います。

次にこれらがインライン化された場合を考えてみます。

参照の場合 std::pair< int , int > x = std::make_pair( 0 , 1 ); pair_swap(x); std::cout << x.first << x.second << std::endl; が std::pair< int , int > x = std::make_pair( 0 , 1 ); std::pair< int , int > &p = x; int t = p.first; p.first = p.second; p.second = t; std::cout << x.first << x.second << std::endl; になります。すると,もはやpがポインタである必要がないので,ただの置換で処理します。 std::pair< int , int > x = std::make_pair( 0 , 1 ); int t = x.first; x.first = x.second; x.second = t; std::cout << x.first << x.second << std::endl; 次に, 全てのアクセスがx.firstかx.secondの形なので, xに連続領域を割り当てる必要がない事が解析され,pairはバラバラに分解されます。 int x_first = 0 ; int x_second = 1 ; int t = x_first; x_first = x_second; x_second = t; std::cout << x_first << x_second << std::endl; 最終的に定数畳み込みで std::cout << 1 << 0 << std::endl; になります。こんな感じで参照を利用すると, 他のコード変換の効果が向上する場合が結構あります。