我今天在 C++ 容器的上下文中了解了这个术语invalidation
。谁能解释一下这是什么意思?
在循环容器时,似乎不允许您以某种方式修改容器的元素。但究竟是什么方式?
请帮助我理解这个话题。
谢谢,博达赛多。
我今天在 C++ 容器的上下文中了解了这个术语invalidation
。谁能解释一下这是什么意思?
在循环容器时,似乎不允许您以某种方式修改容器的元素。但究竟是什么方式?
请帮助我理解这个话题。
谢谢,博达赛多。
容器不会失效——引用容器中元素的迭代器会失效。
迭代器是容器中特定项的句柄。只要该项目保留在容器内,并且容器不会在内部重新排列自身,迭代器就有效。当这两种情况之一发生时,迭代器将失效,因为之后迭代器作为容器的句柄不再有效。
使迭代器无效的最明显方法是从集合中删除其引用项,例如:
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);
}