今天技术群讨论了一个问题,关于stl迭代器失效的,主要是关于vector和map删除元素的,但后来引申出了一个新的问题,特此记录一下。
(一)关于vector和map删除元素
首先是关于vector和map利用迭代器删除元素的方法,代码:
vector<int> test1 = {1,1,1,1,1,1,1}; for (auto iter = test1.begin(); iter != test1.end(); ) { if (*iter == 1) iter = test1.erase(iter); else ++iter; }
首先vector的迭代器在删除元素后会使得该迭代器之后的所有迭代器都失效,所以单纯使用test1.erase(iter)下次再次for循环程序很有可能直接崩溃。而由于vector的erase会返回当前删除元素的下一个元素迭代器,所以将返回值重新赋值给iter,避免了迭代器失效的
问题。
在看下map元素的删除,代码:
map<int, int> test; for (int i = 0; i < 10; ++i) { test[i] = 1; } for (auto iter = test.begin(); iter != test.end(); ) { if (iter->second == 1) { iter = test.erase(iter); } else iter++; }
其实和vector迭代器删除元素类似,也需要将删除后的迭代器返回。早期map的erase返回类型为void(返回删除元素的下一个迭代器是c++11引入的新特性?这句话不确定是否正确,但现在的确可以返回迭代器了),所以map删除元素的方式还可以采用
test.erase(iter++)。
(二)vector迭代器begin()之前是啥?
直接贴测试代码吧:
vector<int> test2 = {1,1,1,1,1,1,1}; cout<<test2[-1]<<endl; vector<int>::iterator iter2 = test2.begin(); --iter2; *iter2 = 5; int a = *iter2; cout<<a<<endl;
结果:
test[-1]指向一个没有初始化的内存区域,但上述操作并没有引起程序崩溃,而且将iter2指向begin()并--iter2后赋值程序也正常输出结果,故该块内存区域是有成功映射到物理页的(不然写一块没有映射的地址,程序就崩了)。
所以,对于删除vector中的元素,之前看到过一种写法为:
vector<int> test2 = {1,1,1,1,1,1,1}; for (auto iter = test2.begin(); iter != test2.end(); ++iter) { if (*iter == 1) { iter = test2.erase(iter); --iter; } }
在最终结果上并没有什么问题,但是第一次删除元素后--iter,iter指向了begin()前面的迭代器,还是尽量不要写成这种形式,依然采用文章中最开始的写法。