invalidation
私は今日、C++コンテナーのコンテキストでこの用語について学びました。誰かがそれが何を意味するのか説明できますか?
コンテナをループするときに、何らかの方法でコンテナの要素を変更することは許可されていないようです。しかし、正確にはどのように?
このトピックを理解するのを手伝ってください。
ありがとう、BodaCydo。
invalidation
私は今日、C++コンテナーのコンテキストでこの用語について学びました。誰かがそれが何を意味するのか説明できますか?
コンテナをループするときに、何らかの方法でコンテナの要素を変更することは許可されていないようです。しかし、正確にはどのように?
このトピックを理解するのを手伝ってください。
ありがとう、BodaCydo。
コンテナは無効になりません-コンテナ内の要素を参照するイテレータは無効になります。
イテレータは、コンテナ内の特定のアイテムへのハンドルです。イテレータは、そのアイテムがコンテナ内に残り、コンテナが内部で再配置されない限り有効です。これらの2つのいずれかが発生すると、イテレータは無効になります。これは、その後、イテレータがコンテナへのハンドルとして無効になるためです。
イテレータを無効にする最も明白な方法は、参照されているアイテムをコレクションから削除することです。例:
std::set<int> s;
s.insert(4);
s.insert(2);
std::set<int>::iterator itr = s.find(4); // itr is a handle to 4
std::cout << *itr << std::endl; // prints 4
s.erase(4); // removes 4 from collection, invalidates itr
std::cout << *itr << std::endl; // undefined behavior
イテレータを無効にするより微妙な方法は、コンテナを内部的に再配置することです(たとえば、内部ストレージを再割り当てします)。これは、たとえば、特定のタイプのコンテナを拡張させることによって実行できます。
std::vector<int> v;
v.push_back(4);
v.push_back(2);
std::vector<int>::iterator itr = v.begin(); // itr is a handle to 4
std::cout << *itr << std::endl; // prints 4
v.push_back(12); // MIGHT invalidate itr, if v expands its internal allocation
一部のコンテナでは、スペースを事前に予約することでこれを防ぐことができます。
std::vector<int> v;
v.reserve(3); // Pre-allocate 3 elements
v.push_back(4);
v.push_back(2);
std::vector<int>::iterator itr = v.begin(); // itr is a handle to 4
std::cout << *itr << std::endl; // prints 4
v.push_back(12); // WILL NOT invalidate itr, since it will never cause v to expand
各STLコンテナのドキュメントには、イテレータの無効化が発生する、または発生する可能性のある状況を説明する必要があります。
基になるコンテナが特定の方法で変更されると、特定のイテレータが無効になります。
例:vector
コンテナのサイズが変更されると、イテレータは無効になります。list
基になるデータが削除されると、イテレータは無効になります。
これは、イテレータが無効になったことを意味します。逆参照しようとすると、例外または未定義の動作が発生する可能性があります。それを操作する試みは、動作することが保証されていません。
オブジェクトの配列(またはリスト)があり、それらをループしている場合は、いくつかのアイテムを削除しました。配列への単純なインデックスは有効でない可能性がありますが、イテレータは有効です。
イテレータの無効化がすべてだと思います。いくつかの例があります:
std::vector<int> v1(10);
std::vector<int> v2(11);
//1
for (std::vector<int>::iterator it = v1.begin(); it != v2.end(); ++it);
//2
for (std::vector<int>::iterator it = v1.begin(); it != v1.end(); ++it)
{
v1.erase(it);
}