c++ - 为什么.end()返回一个无效的迭代器,而不是每次都进行评估(如.size())并检查其是否仍然有效?

标签 c++

我最近了解了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 = 6v.begin()vstd::vector<int>::iteratorint *:
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/

相关文章:

c++ - 如何将从字符串中取出的字符转换为int?

c++ - 通过引用调用与指针参数

C# 结构如 std::set 支持 lower_bound

c++ - 返回指针会弄乱对象(访问冲突)

c++ - 如何将字符串变量名转换为变量的值

C++11随机数生成器UIntType矛盾

c++ - 无法使用迭代器删除 vector 元素, vector 元素实现移动构造函数

c++ - std::map 一键,二值

c++ - 自动调用原始指针的自定义转换器 A* <-> B*

c++ - 什么是左节点和右节点,其中节点可能 > 2