【问题标题】:Decrementing iterator after each loop iteration shows weird behavior每次循环迭代后递减迭代器显示奇怪的行为
【发布时间】:2019-06-19 06:00:17
【问题描述】:

我创建了一个程序来尝试练习列表数据结构的语义。我注意到以下代码有一个奇怪的区别:

第一个代码:

#include<iostream>
#include<list>

using namespace std;

int main() {
    list<int> l;
    int n = 100;
    for(int i = 0; i < n; i++) {
        l.push_back(i);
    }
    list<int>::iterator it = l.end();
    it--;
    for(; !l.empty(); it--) {
        cout << "the size of l is " << (int) l.size() << endl;
        l.erase(it);
    }
}

第二个代码:

#include<iostream>
#include<list>

using namespace std;

int main() {
    list<int> l;
    int n = 100;
    for(int i = 0; i < n; i++) {
        l.push_back(i);
    }
    list<int>::iterator it = l.end();
    it--;
    for(; !l.empty();) {
        cout << "the size of l is " << (int) l.size() << endl;
        l.erase(it--);
    }
}

这两段代码的目标很简单 - 简单地擦除列表中的所有元素。

它们之间唯一的区别是列表迭代器递减的地方。 在第一个代码示例中,我使用了 for 循环控制流来递减迭代器。第二,我使用了后减运算符来减少迭代器。

根据我的理解,上面的代码示例应该是等效的,因为我在从列表中删除一个元素后立即减少了迭代器。此外,根据 STL 文档,只有列表中已擦除元素的迭代器无效。所以不应该有任何未定义的行为。

问题是,第二个代码示例按预期工作 - 它在删除列表中的所有元素后停止。但是,对于第一个样本,列表大小甚至可能变为负数?!当我尝试增加列表中元素的初始数量时,第一个程序中途崩溃。

有人可以告诉我为什么这些代码示例的行为不同吗?

【问题讨论】:

    标签: c++ list debugging iterator


    【解决方案1】:

    第一个代码具有未定义的行为。正如你所说,erase 使迭代器无效,之后评估的 it-- 导致 UB。

    第二个代码很好;请注意,评估顺序不同。 it-- 将递减迭代器,然后返回原始值(这是后递减运算符的要点)。原始值稍后传递给erase。减量发生在erase 之前,所以没关系。

    【讨论】:

    • +1 感谢您的澄清。我将其解释为,擦除首先发生,然后是递减。因此,我搞砸了。
    • 也就是说,由于递减运算符返回原始迭代器的值,所以erase可能发生,并且迭代器仍然有效。与其他代码相反,它减少了已经无效的迭代器。只是试着用不同的方式表达,也许更多的人会更容易理解。
    • @LanceHAOH 你一定错过了后减运算符的好处。 :)
    • @ChristinaJacob 未定义行为 = 任何事情都可能发生。
    • @LanceHAOH 换个角度看,作为一个操作符(或函数),当它返回时,调用结束。返回后无法执行减量。所以它必须执行递减然后返回复制的原始值。
    最近更新 更多