关于vector的erase删除操作的两种不同方法,在linux与visual studio的实现讨论
1.前言:
最近在做某一个题时,用到了vector的删除操作,利用的是erase()函数删除符合条件的函数,然后和同学讨论的时候,同学给了一个写法,网上也搜到了一个写法,但是发现了问题。
2.测试代码:
定义一个vector 删除指定元素, 这里是删除1
#include <vector>
#include <iostream>
using namespace std;
int main() {
vector <int> arr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
arr.push_back(4);
arr.push_back(5);
for (auto i = arr.begin(); i != arr.end(); i++) { // 第一种写法
if (*i == 1) {
i = arr.erase(i);
i--;
}
}
for (auto i = arr.begin(); i != arr.end();) { // 第二种写法
if (*i == 1) {
i = arr.erase(i);
} else {
i++;
}
}
for (auto i = arr.begin(); i != arr.end(); i++) { //输出
cout << *i << " ";
}
cout << endl;
return 0;
}
3.讨论
这两种写法, 看起来是基本相同的,基本想法就是每一次循环 删除了迭代器那么不自增迭代器,反之,则自增迭代器, 实则不然,如果一上来就删除首元素, 那么问题就来了 方法一的i在自减之后不是出了小于arr.begin()了吗。别急我们看下面的实践。
4.测试
ubuntu
在ubuntu下可以运行而且不出错
这里进入gdb调试 查看迭代器i的变化
**在删除元素后 迭代器自减后竟然是有地址的 此时地址是arr.begin()的前面一个地址, 也就是说i可以变成
arr.begin() - 1**
迭代器自加后 迭代器变成了arr.begin()
visual studio
运行时错误,出错在 i–;
因为i–后 i变成了arr.begin() - 1 而visual studio不支持这样的写法,所以报错
5.总结
vector如果简单想象成数组arr的话,在首元素i–,i = (arr - 1),但我们并没有在这个状态下解引用。然后i++加回去又回到可解引用的地址值,不出事也是可以理解的, gnu对list的实现是双向循环链表 ++list.end() 后就变成 list.begin()。但vs会assert说越界