我创建了一个程序来尝试对列表数据结构的语义进行练习。我注意到以下代码段有一个怪异的区别:
第一个代码:
#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文档,仅列表中被删除元素的迭代器无效。因此,不应有任何未定义的行为。
问题是,第二个代码示例按预期方式工作-擦除列表中的所有元素后停止。但是,对于第一个样本,列表大小甚至可能变为负数!当我尝试增加列表中元素的初始数量时,第一个程序崩溃了一半。
有人可以建议我这些代码示例为何表现不同吗?
答案 0 :(得分:5)
第一个代码具有未定义的行为。如您所说,erase
使迭代器无效,it--
之后求值导致UB。
第二个代码很好;请注意,评估顺序不同。 it--
将递减迭代器,然后返回原始值(这是后递减运算符的作用)。原始值稍后会传递到erase
。递减发生在erase
之前,所以很好。