vector中使用erase操作删除迭代器的问题(避免野指针)以及end的地址变化
在vector中,使用erase来剔除对应的元素,但是使用iterator的时候需要注意不要让iterator变成野指针
vector的erase
在C++ Reference 中,对erase的说明如下:
vector::erase - C++ Reference http://www.cplusplus.com/reference/vector/vector/erase/
//c++98
iterator erase (iterator position);
iterator erase (iterator first, iterator last);
//c++11
iterator erase (const_iterator position);
iterator erase (const_iterator first, const_iterator last);
Erase elements
Removes from the vector either a single element (position) or a range of elements ([first,last)).
This effectively reduces the container size by the number of elements removed, which are destroyed.
可以看到erase方法可以删除vector中的一个元素,或者删除一个范围
参数说明:
position: 在vector中删除的元素的位置
first, last: 在vector中的范围[first, last),即 >= first, < last
demo
// erasing from vector
#include <iostream>
#include <vector>
using namespace std;
int main ()
{
vector<int> myvector;
// set some values (from 1 to 10)
for (int i=1; i<=10; i++){
myvector.push_back(i);
}
// erase the 6th element
myvector.erase (myvector.begin()+5);
// erase the first 3 elements:
myvector.erase (myvector.begin(),myvector.begin()+3);
cout << "myvector contains:";
for (unsigned i=0; i<myvector.size(); ++i){
cout << ' ' << myvector[i];
}
return 0;
}
对vector直接使用erase操作,删除对应的元素。输出结果如下:
对iterator使用erase
如果直接对iterator进行erase操作,被删除的迭代器将会失效
错误的demo
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> vecInt;
//vecInt: 0, 1, 2, 3, 4, 444
for(int i = 0; i != 5; i++){
vecInt.push_back(i);
}
vecInt.push_back(444);
//erase the element 444
for(vector<int>::iterator iter = vecInt.begin(); iter != vecInt.end(); iter++){
if(*iter == 444){
vecInt.erase(iter);
}
}
for(int i : vecInt){//c++11
cout << i << " ";
}
return 0;
}
在执行erase的for循环中,判断iter指向的元素是不是444,如果是444就执行vecInt.erase(iter)。此时iter迭代器被erase,iter指向了一个不确定的地址成为野指针,在for循环的条件中,iter++会导致程序崩溃。
修改后的demo
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> vecInt;
//vecInt: 0, 1, 2, 3, 4, 444
for(int i = 0; i != 5; i++){
vecInt.push_back(i);
}
vecInt.push_back(444);
for(int i : vecInt){//c++11
cout << i << " ";
}
//vecSize should be 6
cout << endl << "size of vector: " << vecInt.size() << endl;
//erase the element 444
for(vector<int>::iterator iter = vecInt.begin(); iter != vecInt.end(); iter++){
if(*iter == 444){
iter = vecInt.erase(iter);
iter--;
}
}
for(int i : vecInt){//c++11
cout << i << " ";
}
//vecSize should be 5
cout << endl << "size of vector: " << vecInt.size() << endl;
return 0;
}
在删除元素444的时候,判断iter指向的值,用iter = vecInt.erase(iter);使iter指向erase之后的下一位,由于在for循环条件中有iter++,所以此时需要再iter- -,才能保证遍历所有元素。
运行结果如下:
Tips
在使用vector.erase(iterator)的时候需要时刻注意iterator指向的位置,使用 iterator = vector.erase(iterator) 防止变成野指针程序崩溃。
vector中erase时,iterator的地址变化
在vector中,begin指向vector的起始地址,end指向vector末尾元素的后一个地址。用iterator指向begin,并不断的erase操作,end的地址变化情况如下:
Demo
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> vecInt;
//vecInt: 10, 11, 12, 13, 14
for(int i = 10; i != 15; i++){
vecInt.push_back(i);
}
//show all elements
cout << "show all elements: " << endl;
for(int i : vecInt){
cout << i << " ";
}
cout << "\n===============================\n" << endl;
//address of begin and end
cout << "address of vecInt: " << endl
<< "begin: \t" << &(*vecInt.begin()) << ", value: " << *vecInt.begin() << endl //使用&*iter来读取iter的地址
<< "end: \t" << &(*vecInt.end()) << endl;
cout << "\n===============================\n" << endl;
//address of iter and end with erase
vector<int>::iterator iter = vecInt.begin();
while(iter != vecInt.end()){
iter = vecInt.erase(iter);
cout << "add of iter: " << &*iter << ", add of end: " << &*vecInt.end() << endl;
}
return 0;
}
在代码中,使用&*iter的方式,来获取迭代器的地址
(参考文档:如何获取vector的一个迭代器iterator的地址 - Zero’s Zone - ****博客 https://blog.****.net/hl_zzl/article/details/84575713 )
运行结果如下:
可以看到,**在执行erase删除元素的过程中,iter的地址不变,**当前元素被删掉之后,剩下的元素前移,end的地址随之向前移动。