在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 - CSDN部落格 https://blog.csdn.net/hl_zzl/article/details/84575713 )
運作結果如下:
可以看到,**在執行erase删除元素的過程中,iter的位址不變,**目前元素被删掉之後,剩下的元素前移,end的位址随之向前移動。