イテレーターは、ポインタのようにSTLコンテナの要素を参照できるオブジェクトです。これらは、任意のコンテナ(vector、list、mapなど)の要素への統一的なアクセス方法を提供します。イテレーターにはいくつかの種類があります:
イテレーターのライフサイクルに特に注意が必要です:
例:
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した後もイテレーターが削除された要素に結びついたままで(未定義の動作)、その後のアクセスでランダムなクラッシュを引き起こしました。