ProgrammingC++ 開発者

C++ STLにおけるイテレーターとは何であり、どのような種類が存在し、プログラミングの際に知っておくべき使用上の注意点は何ですか?

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

回答

イテレーターは、ポインタのようにSTLコンテナの要素を参照できるオブジェクトです。これらは、任意のコンテナ(vector、list、mapなど)の要素への統一的なアクセス方法を提供します。イテレーターにはいくつかの種類があります:

  • InputIterator — 順方向にシーケンスを読み取るためのもの。
  • OutputIterator — シーケンスに値を書き込むためのもの。
  • ForwardIterator — 順方向に読み書きするためのもので(OutputIteratorよりも長生きします)。
  • BidirectionalIterator — 順方向および逆方向に移動できるもの。
  • RandomAccessIterator — 任意のアクセスをサポートするもの(例:std::vector::iterator)。

イテレーターのライフサイクルに特に注意が必要です:

  • コンテナを変更すると、コンテナのイテレーターは無効化されることがあります。たとえば、vectorに要素を挿入すると、古いイテレーターは無効になる可能性があります。
  • 異なるコンテナは、イテレーターのライフサイクルを異なる方法で管理します。std::listでは、挿入や削除が他のイテレーターを無効にしませんが、std::vectorではほぼ常に無効になります。

例:

std::vector<int> v = {1,2,3,4,5}; for (auto it = v.begin(); it != v.end(); ++it) { if (*it == 3) { // 値3の要素を削除します it = v.erase(it); // eraseは次の要素へのイテレーターを返します --it; // 必要に応じてイテレーターを調整します } }

注意が必要な質問

質問: std::vector::insertを呼び出すと、イテレーターは無効になりますか?
よくある答え: いいえ、範囲の終わりを超える場合のみ。
正しい答え: 挿入位置またはその後の位置に等しいまたはそれに等しいすべてのイテレーターと参照は、コンテナの容量が増加した場合には無効になります。容量が十分な場合、挿入点の後の範囲内のイテレーターのみが無効になります。

例:

std::vector<int> v = {1,2,3}; auto it = v.begin() + 1; v.insert(v.begin(), 0); // ここでitが無効になる可能性があります!

知識不足から生じた実際のエラーの例


物語: プロジェクトでstd::vectorをイテレートするためにポインタが使われ、push_backの後に無効化されたポインタでイテレーションが続行され、その結果アプリケーションがクラッシュしました。



物語: 開発者はfor(auto it : list)のループ内でeraseを通じてstd::listの要素を削除し、返されたeraseイテレーターを使用しなかったため、イテレーションが要素をスキップし、必要なすべての要素が削除されませんでした。



物語: コード内でstd::mapが使用され、キーでeraseした後もイテレーターが削除された要素に結びついたままで(未定義の動作)、その後のアクセスでランダムなクラッシュを引き起こしました。