左辺値参照(C++)
C++ の仕様:インデックス への移動
C プログラミング言語では、引数は値渡ししかできません。 C++ では、値渡しも参照渡しも可能です。 C++ の参照型(ポインタ型に似たもの)では、オブジェクトのエイリアスが作成されます。
メモ: C++ に固有のポインタ参照/逆参照については、「参照演算子と間接参照演算子」で説明しています。
演算子 & を使って左辺値参照を作成することができます。
int i = 0;
int &ir = i; /* ir is an alias for i */
ir = 2; /* same effect as i = 2 */
このコードでは、左辺値 ir を i のエイリアスとして作成しています(初期化子は参照と同じ型でなければなりません)。 ir に対して操作を行うと、i に対して操作を行った場合とまったく同じ結果になります。 たとえば、ir = 2 とすると i に 2 が代入されますし、&ir は i のアドレスを返します。
参照引数
参照宣言子を使って関数の参照型パラメータを宣言することもできます。
void func1 (int i);
void func2 (int &ir); // ir is type "reference to int"
// ...
int sum = 3;
func1(sum); // sum passed by value
func2(sum); // sum passed by reference
参照渡しされた引数 sum は、func2 で直接変更することができます。 それに対して、func1 は引数 sum(値渡し)のコピーを受け取るため、sum 自体を func1 で変更することはできません。
実引数 x を値渡しすると、対応する関数内の仮引数は x のコピーを受け取ります。 関数本体でこのコピーを変更しても、関数のスコープ外にある x の値には反映されません。 もちろん、関数から値を返し、それを使って後で x を変更することは可能ですが、値渡しされたパラメータを関数が直接変更することはできません。
C で、関数のスコープ外にある関数パラメータの値を変更するには、パラメータのアドレスを渡す必要があります。 このアドレスは値渡しされるため、アドレスの内容を変更すると、関数のスコープ外のパラメータの値に反映されます。
関数でパラメータの値を変更する必要がない場合でも、関数にアドレス(参照)を渡すのはやはり有益です。 それが顕著なのは、パラメータが大規模なデータ構造やオブジェクトである場合です。 オブジェクトを関数に直接渡すと、オブジェクト全体をコピーしなければなりません。
次の 3 つの関数実装を比較してください。
#1 | #2 | #3 |
int treble_1(int n)
{
return 3 * n;
}
// ...
int x, i = 4;
x = treble_1(i);
/* x now = 12, i = 4 */
|
void treble_2(int* np)
{
*np = (*np) * 3;
}
// ...
treble_2(&i);
/* i now = 2 */
|
void treble_3(int &n/* n is a reference type */)
{
n = n * 3;
}
// ...
treble_3(i);
/* i now = 36 */
|
仮引数を type& t と宣言すると、t は "type の参照" 型となります。 そのため、実引数 i を渡して treble_3 を呼び出すと、i を使って仮参照引数 n が初期化されます。 その結果、n は i のエイリアスとなり、n = n*3 を実行すると i にも 3 * i が代入されます。
初期化子が定数であるか参照型とは別の型のオブジェクトである場合には、一時オブジェクトが作成され、参照はそのエイリアスとなります。
int& ir = 6; /* temporary int object created, aliased by ir, gets value 6 */
float f;
int& ir2 = f; /* creates temporary int object aliased by ir2;
f converted before assignment */
ir2 = 2.0; /* ir2 now = 2, but f is unchanged *
一時オブジェクトを自動的に作成することで、仮引数と実引数の型が異なる(ただし代入互換性はある)場合に参照型の変換を行えるようになります。 もちろん、値渡しの場合には、変換の問題は少なくなります。仮引数に代入する前に、実引数のコピーを物理的に変更できるからです。