ProgrammingC++ミドル開発者

C++におけるoperator[]とは何ですか?ユーザー定義コンテナのためにこの演算子を正しくオーバーロードする方法は?

Hintsage AIアシスタントで面接を突破

回答。

インデックスアクセス演算子 operator[] は、ユーザー定義コンテナ(配列のような)オブジェクトのインデックス付け構文を提供するためにC++でオーバーロードできる演算子です。

歴史的背景:

C言語、そしてその後のC++において、演算子 [] は配列の要素にインデックスで迅速かつ簡便にアクセスできるようにしていました。しかし、コンテナクラスの人気が高まるにつれて、同じ構文をユーザー定義データ型に移行する必要が出てきました。

問題:

インデックスアクセス演算子の正しい設計は、定数性、範囲外アクセスの安全性(out-of-bounds)、返り値の選択、および参照またはポインタの有効性保証に関する問題を伴います。

解決策:

C++ではクラスのためにoperator[]をオーバーロードすることで、インデックスで要素にアクセスできるようにし、"配列のような動作"を実現できます。通常(非定数オブジェクト用)および定数(定数オブジェクト用)の両方のバージョンの演算子を実装する必要があります。

コードの例:

class MyArray { int data[10]; public: int& operator[](size_t index) { return data[index]; } const int& operator[](size_t index) const { return data[index]; } }; MyArray arr; arr[3] = 42; // OK const MyArray& const_arr = arr; int val = const_arr[3]; // OK

主な特徴:

  • 常にconstおよび非constバージョンの演算子を実装して、定数オブジェクトとの正しい動作を確保する
  • 範囲外チェックを行わない(標準コンテナの.at()とは異なる)
  • 返り値の型(参照、ポインタ、値)を意識的に選択することが重要

トリッキーな質問。

operator[]から参照を返すことは必須ですか?

いいえ — しかし、値を返すと、構文 arr[i] = x; は機能しません(代入ではなくコピーを行うことになります)。コンテナの慣習的な意味を保つために、通常は参照を返します。値を返すと、要素への書き込みができません:

int operator[](size_t idx); // arr[2] = 10; これはコンパイルできません

operator[]は範囲をチェックするべきですか?

標準では要求されていません。クラシックなoperator[](std::vectorのような)はそのようなチェックを行いません。標準コンテナは、範囲外アクセスの場合に例外をスローする別のメソッド.at()を導入しています。

operator[]は定数メソッドであるべきですか?

いいえ — もし非定数参照を返す場合は。しかし、operator[]は定数オブジェクトおよび非定数オブジェクトの両方に対してオーバーロードする必要があります。これにより、コンテナが直感的かつ安全に動作します。

一般的な間違いとアンチパターン

  • 定数バージョンの演算子を実装しない(これによりconst参照を通じて要素にアクセスできなくなる)
  • 値を返し、参照を返さず、代入の意味を壊す
  • コンテナ内の未初期化の要素を放置する

実生活の例

ネガティブケース

若い開発者がoperator[]の非定数バージョンのみを実装し、値を返していました。その結果、コンテナにconst参照でアクセスできず、書き込みを試みると変な動作をする—値が保存されませんでした。

利点:

  • 非定数オブジェクトを使用している限り、コンパイルが成功する

欠点:

  • 期待されるC++の意味が破壊された
  • const-correctnessが機能しない、標準アルゴリズムがサポートされない

ポジティブケース

コンテナMyArrayでは、両方のバージョンのoperator[]が実装されており、正しく参照が返されます。必要に応じて、範囲チェックのためのメソッドat()が追加されました。

利点:

  • コンテナは「標準に従った」動作をする
  • すべてのモード(const、非定数、読み取り、書き込み)がサポートされる

欠点:

  • operator[]を使用しても、範囲外アクセスのエラーが発生する可能性がある
  • クラスの複雑さがわずかに増加する