首页 > 解决方案 > 为什么 .end() 可以返回一个无效的迭代器,而不是每次都被评估(如 .size())并检查它是否仍然有效?

问题描述

我最近了解了 C++ 中的迭代器无效化。我不明白为什么.end()for 循环中的函数可以返回无效的迭代器,因为它是一个 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()每次迭代之前都没有完成。从逻辑上思考,循环怎么可能工作……

标签: c++

解决方案


基本上是动态分配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()is v = 6, v.begin()isvstd::vector<int>::iteratoris 的相似之处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无效,它指向一块被释放的内存。


推荐阅读