1. 導入:なぜ配列への参照が必要なのか
C++の現場では、配列を関数に渡す際に「ポインタへの崩壊(decay)」という現象がよく問題になります。関数に配列を渡す際、通常は int などに変換されてしまうため、配列のサイズ情報が失われ、sizeof演算子でサイズを取得できなくなります。
この課題を解決するのが「配列への参照」です。これを使うことで、配列のサイズを型情報として保持したまま、安全かつ直感的に関数へ渡すことが可能になります。
2. 基礎知識:配列への参照とは
配列への参照とは、その名の通り「配列そのもの」を指し示す別名(エイリアス)です。
通常のポインタによる受け渡しでは、渡された側は「配列の先頭アドレス」しか知り得ませんが、配列への参照を使用すると、コンパイラに対して「この引数はサイズNの配列である」という情報を明示できます。これにより、関数内で配列の長さを誤認するリスクを排除し、境界チェックをコンパイル時に行えるようになります。
3. 実装/解決策:構文のポイント
配列への参照を宣言する際の構文は少し特殊です。
int (&ref)[3] = arr;
このように、変数名の前に「&」を付け、括弧で囲むのがポイントです。括弧を忘れると「参照の配列」という全く別の型(宣言不可)として解釈されてしまうため注意が必要です。
4. サンプルプログラム
以下は、配列への参照を用いて、関数内で正確にサイズを取得する実用的な例です。
include <iostream>
// 配列への参照を引数として受け取る関数
// テンプレートを使うことで、任意のサイズ・型の配列に対応可能
template <typename T, std::size_t N>
void printArray(T (&arr)[N]) {
// コンパイル時に配列のサイズNが確定しているため安全
std::cout < < "配列のサイズ: " < < N < < std::endl;
for (std::size_t i = 0; i < N; ++i) {
std::cout < < arr[i] < < " ";
}
std::cout < < std::endl;
}
int main() {
int data[] = {10, 20, 30};
// 配列そのものを渡す
printArray(data);
return 0;
}
5. 応用・注意点:現場で陥りやすい罠
1. テンプレート化の推奨
上記の例のように、テンプレート(template <std::size_t N>)と組み合わせるのが実務上のベストプラクティスです。ハードコードされたサイズ(例: &int (&ref)[3])を指定すると、サイズが異なる配列を渡した瞬間にコンパイルエラーになるため、汎用性が著しく低下します。
2. std::arrayとの併用検討
C++11以降では、生配列よりも std::array の使用が推奨されます。std::arrayであれば、参照渡しをする際も型情報が維持され、配列への参照のような特殊な構文を意識することなく、より安全に扱うことができます。
3. 寿命の管理
参照はあくまで「別名」であるため、元の配列がスコープ外に出た後に参照を利用すると、未定義動作(ダングリング参照)を引き起こします。ローカル変数の配列を関数から返すような実装は絶対に避けてください。
これらを意識することで、より堅牢で保守性の高いC++コードを記述できるようになります。

コメント