天天看點

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的位址随之向前移動。

繼續閱讀