STL (C++)-erase(iterator++)这样些对吗?为什么错了?(假设iterator是vector<int>的迭代器)

WP主题Bug提交 WP主题Bug提交 主题:1067 回复:2226

STL (C++)-erase(iterator++)这样些对吗?为什么错了?(假设iterator是vector<int>的迭代器)

甜柠檬 发布于 2016-12-17 字数 278 浏览 1057 回复 2

个人偏向这样理解:erase(iterator++)在两个序列点中iterator改变了两次,第一次被erase,第二次自加;因为标准规定,在两个序列点之间,一个对象所保存的值最多只能被修改一次。
还有一种理解:是在iterator自加之前被erase了,使得iterator指向未知,所以在对其自加时,导致程序崩溃

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

支持 Markdown 语法,需要帮助?

评论(2

瑾兮 2017-03-03 2 楼

当iterator 的类型是std::vector<int>::iterator的时候,erase(iterator++)这样的写法是错误的。例如:

int main( )
{
std::vector<int> vi;
for(int i = 0; i < 10; i++)
{
vi.push_back(i);
}
for (std::vector<int>::iterator i = vi.begin(); i != vi.end(); i++) {
std::cout << i << " ";
}// output 0 1 2 3 4 5 6 7 8 9
std::cout << 'n';
std::vector<int>::iterator iter = vi.begin();
vi.erase(iter++); // 该行设置断点
cout <<
iter << endl; // 发生断言错误
}

在设置断点的一行,在vs2010中按F11单步调试,你会发现:

iter++操作将iter加1后将还没有加一的值赋给临时变量_tmp,_tmp迭代器此时指向vector的开头,即元素0,iter此时指向_tmp的下一个元素即元素1。_tmp在iter++操作后返回给erase()。
erase()将_tmp所指向的元素(即0)删除。
注意该处erase还执行了其他的操作 这也是为什么以数组存储方式的容器(例如vector)和以类似链表存储方式的容器(例如list)的区别。erase() 删除了vector容器开头元素之后,类似于数组的做法,还函数还将删除元素之后所有的元素往前挪了一个位置。此时vector 元素的排列顺序是1 2 3 4 5 6 7 8 9 9。
接下来再将最后一个元素9删除,释放其存储空间。

这个时候iter指向的位置还是容器开始位置的下一个位置,也就是2! 而不是我们想要的1。调试的过程中可发现这一点。但是该程序运行时发生了assertion failure。原因是编译器起到了很好的保护机制:猜测当erase()函数返回之前,所有与指向容器iv的迭代器都打上的失效的标记,接下来再使用这些迭代器就会发生断言错误。

虐人心 2017-01-26 1 楼

这个要区分两种情况吧,一种是如数组类的容器 deque,vector,string.
这种情况下只要erase(iterator) 就好了。

另一种是map,set这样的结点型的容器。
则需要使用你这种erase(iterator++),才会跳到下一个。