我最近了解了c++中的迭代器invalidaiton。我无法理解为什么for循环中的.end()
函数会返回无效的迭代器,而由于它是for循环,因此每次循环运行时都会导致对.end()
的函数调用,就像基于索引的for循环会.size()
。
引擎盖下是否正在进行某种缓存?每次都不调用.end()
吗?如果.end()
函数将检查迭代器在上一次循环迭代中是否已更改,我们是否可以修复无效的迭代器?
发生了什么,最重要的是,为什么有区别(使用.size()
)?
我必须立即更新迭代器的示例代码:
std::vector<int> v {0, 1, 2, 3, 4, 5};
for (auto it = v.begin(); it != v.end(); ++it) {
if (*it == 5 && std::next(it) == v.end()) {
v.resize(v.size() + 1);
it = std::next(v.begin(), v.size() - 2);
*std::next(it) = 999;
*it = 0;
}
}
如果调整大小后不执行
it = std::next(v.begin(), v.size() - 2);
,则迭代器无效。.size()
索引循环变量不需要这样做:for (size_t i = 0; i < v.size(); ++i) {
if (v.at(i) == 5 and (i+1) == v.size()) {
v.resize(v.size() + 1);
v.at(i + 1) = 999;
v.at(i) = 0;
}
}
更新:感谢您在答案和评论中的解释。不是
.end()
函数使迭代器无效。整个it
对象是无效的,而且我不知为何错过了for循环中的begin语句auto it = v.begin()
并非在每次迭代之前完成的事实。从逻辑上思考,那么循环怎么可能会工作……
最佳答案
基本上,std::vector<int>
是动态分配的int *
数组的包装。因此,让我们看一下如何遍历数组。
我们可以使用大小进行迭代。此处6
在您的代码中与v.size()
相对应:
int *v = new int[6]{0, 1, 2, 3, 4, 5};
for (size_t i = 0; i < 6; ++i) {
// do something with `v[i]`
}
delete[] v;
可以使用指针重写相同的循环。与
std::vector
的相似之处:v.end()
是v = 6
,v.begin()
是v
和std::vector<int>::iterator
是int *
:int *v = new int[6]{0, 1, 2, 3, 4, 5};
for (int *it = v; it != v + 6; ++it) {
// do something with it
}
delete[] v;
现在,当我们调整数组大小时,我们分配新的内存并复制数据并释放旧的内存,然后将指针重新分配给新的内存区域:
int *v = new int[6]{0, 1, 2, 3, 4, 5};
for (int *it = v; it != v + 6; ++it) {
if (*it == 5 and it + 1 == v + 6) {
// resize
{
int *temp = new int[7]; // allocate new array
std::copy(v, v + 6, temp); // copy elements
delete[] v; // delete old array
v = temp; // reassign pointer
}
// Oops! `it` points into `v` that was `delete[]`d above!
}
}
delete[] v;
由于删除了旧数组,因此指针
it
无效,它指向已释放的内存。
关于c++ - 为什么.end()返回一个无效的迭代器,而不是每次都进行评估(如.size())并检查其是否仍然有效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61573820/