天天看点

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操作,删除对应的元素。输出结果如下:

vector中使用erase操作删除迭代器的问题(避免野指针)以及end的地址变化

对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- -,才能保证遍历所有元素。

运行结果如下:

vector中使用erase操作删除迭代器的问题(避免野指针)以及end的地址变化

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 - CSDN博客 https://blog.csdn.net/hl_zzl/article/details/84575713 )

运行结果如下:

vector中使用erase操作删除迭代器的问题(避免野指针)以及end的地址变化

可以看到,**在执行erase删除元素的过程中,iter的地址不变,**当前元素被删掉之后,剩下的元素前移,end的地址随之向前移动。

继续阅读