迭代器结束检查在“for”循环内递增后失败

Iterator end check fails after incrementing inside a `for` loop

本文关键字:失败 循环 检查 结束 for 迭代器      更新时间:2023-10-16

这个问题很可能是重复的,但我没有找到关于这个问题的任何内容。

为什么递增放置在vector中最后一个位置的iterator会使它不等于vector.end()

或者,换句话说,为什么这正常执行:

int main() {
    vector<string> vec = {"ve"};
    for (auto it = vec.begin(); it != vec.end(); it++) {}
    return 0;
}

虽然这个进入了一个无限循环:

int main() {
    vector<string> vec = {"ve"};
    for (auto it = vec.begin(); it != vec.end(); it++) { it++; }
    return 0;
}

而这个:

int main() {
    vector<string> vec = {"ve"};
    for (auto it = vec.begin(); it != vec.end(); it++) {
        cout << (it == vec.end()) << " ";
        cout << (*it == "ve") << endl;
        it++;
    }
    return 0;
}

导致打印SEGFAULT

0 1
0

因此,it实际上被递增了,因此其内容变为空(根据调试器进行了优化(,但它并没有等于vec.end()。为什么?

想象一下itvec.end()之前指向一个,据说是for循环的最后一次迭代。

  1. it != vec.end();将被true,因此循环将继续。
  2. 执行体内的it++;it == vec.end()现在。
  3. 执行来自for环路头的it++it点一个超越vec.end().

vec.end()指向vec的最后一个元素之外的一个元素,它仍然是明确定义的。 vec.end() + 1(it的最终值(指向vec的最后一个元素之外的两个元素,这是未定义的行为。

这意味着取消引用迭代器会访问未分配的内存(解释分段错误(。再次未定义的行为。

您正在检查it != vec.end()但是由于it++发生了两次,您在每次检查时跳过两次。换句话说,你跑过了vector的尽头而没有发现它。

如果你在向量中添加一个元素,那么循环将到达终点并停止,因为你将不再跳过终点(显然这不是一个"正确的"修复,它只是演示了问题(。

要修复它,请在循环中的增量之前检查结束。您也可以检查在条件中使用operator<,但这有点风险,因为您将无效it保留一段时间,这对将来的代码维护不利。

在 for 循环中,迭代器上的增量操作是循环中的最后一个(也是隐式(操作。

情况 1:循环以 "it" = vec.begin(( 开头。什么也没发生。"它"递增(隐式(。它 = vc.end((。循环结束。因此是正常行为。

情况 2:循环以它开头 = vec.begin((。"它"递增。它 = vc.end((。"它"再次递增(隐式(。"它"移动到下一个内存位置,并在每个周期中不断增加。因此,无限循环。

情况 3:循环以它开头 = vec.begin((。检查是否 == vc.end((。返回假。打印"it"引用的内存位置中的值。"它"递增。它 = vc.end((。"它"再次递增(隐式(。"it"移动到下一个未分配的内存位置。因此,SEG故障。