参照: ポインタより安全な「あだ名」
C++の重要な機能。NULLにならず、再束縛もできない安全なポインタとして理解する。
参照 (Reference)
既存の変数に対する別名(あだ名)。実体は同じ。
別名 (Alias)
参照の役割そのもの。
初期化 (Initialization)
変数を宣言すると同時に値を設定すること。参照は宣言時の初期化が必須。
const参照
const修飾子が付いた参照。参照先を読み取ることしかできない。
詳細解説
なぜ参照が必要か?
参照は主に2つの目的で使われます。
- 安全性: 参照は宣言時に必ず初期化が必要で、NULLになることがありません。これにより、ポインタで頻発するNULLポインタアクセスエラーをコンパイル時点で防げます。
- 可読性: 関数に参照を渡すと、呼び出し側のコードがすっきりします。値渡しのように見えながら、実際には参照として機能するため、コードの意図が明確になります。
// int 型の変数 original を宣言し、10 で初期化int original = 10;
// original への参照 alias を作成// これ以降、alias は original と全く同じものを指すint& alias = original;
// 参照(あだ名)を使って値を変更alias = 20;
// original(本名)の値も変わっている// 出力: original: 20, alias: 20std::cout << "original: " << original << ", alias: " << alias << std::endl;
// 参照は NULL にできず、必ず初期化が必要// int& no_init; // コンパイルエラー// int& null_ref = nullptr; // コンパイルエラー実行結果
original: 20, alias: 20
ポインタ vs 参照 徹底比較
どちらも変数のメモリアドレスを扱う点で似ていますが、重要な違いがあります。
| 特性 | ポインタ (`*`) | 参照 (`&`) |
|---|---|---|
| NULLにできるか | はい (<code>nullptr</code>) | いいえ |
| 初期化 | 宣言時に必須ではない | 宣言時に必須 |
| 再束縛(指す相手の変更) | 可能 | 不可能 |
| 値へのアクセス | デリファレンス (`*`) が必要 | 不要(変数と同様に扱う) |
| 主な用途 | 動的メモリ確保、配列、指す相手が変わる可能性 | 関数引数・戻り値、エイリアス |
// ポインタ版: アドレスを渡す必要があり、呼び出し側が冗長void swap_ptr(int* a, int* b) { if (a == nullptr || b == nullptr) return; // NULLチェックが必須 int temp = *a; *a = *b; *b = temp;}
// 参照版: 呼び出しが自然で、NULLの心配がないvoid swap_ref(int& a, int& b) { int temp = a; a = b; b = temp;}
int x = 5, y = 10;swap_ptr(&x, &y); // アドレスを渡すswap_ref(x, y); // 値を渡すように見える実践テクニック
<code>const</code>参照による効率的な関数渡し
関数に大きなオブジェクト(クラスや構造体)を渡すとき、値渡しをするとオブジェクト全体のコピーが発生し、パフォーマンスが低下します。これを避けるため、「const参照」を使うのがC++の定石です。これにより、コピーを防ぎつつ、関数内でオブジェクトが誤って変更されることも防止できます。
// 巨大なオブジェクトを想定struct BigObject { // ... たくさんのデータ ... std::string data;};
// ❌ Bad: 値渡し。BigObject全体のコピーが発生し、非効率。void process_by_value(BigObject obj) { std::cout << obj.data << std::endl;}
// ✅ Good: const参照渡し。コピーが発生せず、読み取り専用で安全。void process_by_const_ref(const BigObject& obj) { // obj.data = "new value"; // コンパイルエラー!変更できない std::cout << obj.data << std::endl;}演習課題
課題1: 参照渡し
引数で受け取った`int`型の変数の値を1増やす`increment`という関数を、参照を使って実装してください。
解答例を見る
void increment(int& value) { value++;}
int main() { int counter = 10; increment(counter); // counter は 11 になる return 0;} 課題2: ポインタから参照へ
ポインタを受け取ってその値を表示する関数を、参照を受け取るようにリファクタリングしてください。呼び出し側のコードはどう変わりますか?
合格ライン
参照が変数の「あだ名」であることを自分の言葉で説明できる
ポインタと参照の主な違いを3つ挙げられる(NULL, 再束縛, 初期化)
関数に大きなオブジェクトを渡す際に`const`参照がなぜ良いかを説明できる
参考リンク
C++ reference - cppreference.com - (公式に近い信頼性の高いリファレンス)
C++ Super-FAQ - References - (よくある質問とその答え)