erase()函數的功能是用來刪除容器中的元素
函數原型:
iterator erase(iterator where);
iterator erase(iterator first,iterator last);
basic_string& erase(size_type p0=0,size_type n=np);
刪除某個容器里的某個元素:c.erase(T);
看似一個簡單的動作,然而對不同類型的容器,內部卻做了截然不同的事情,后面介紹。
假設有這樣一個題目,將某個容器中所有滿足條件N == X的元素刪除,按照常規的思路應該有類似這樣的代碼:
// 假設Container和container分別表示一種容器和對應的一個對象
Container<T>::iterator it;
for (it = container.begin(); it != container.end(); ++it) {
if (N == X)
container.erase(it);
}
然而這樣的代碼對于任一種容器都是錯誤的
容器按內存分配方式可以分為鏈表容器和數組容器。
所謂的鏈表容器指的是一種表現方式,包括list、slist等這樣基于節點的容器(動態分配內存塊)和set、map、multiset、multimap等關聯容器(平衡樹實現),而數組容器指的是在一塊連續的內存上保存元素的連續內存容器,比如vector、deque、string等。
OK,現在說說erase對他們的操作,鏈表容器以list為例,當執行container.erase(it)時,確實第一個滿足條件的元素刪除了,但這時it指針已經被刪除了,它也不指向任何元素了,所以也只能到此為止了,也就是說上面的代碼對于鏈表容器來說只能正確刪除第一個滿足條件的元素,針對這個問題我們首先想到的就是在刪除指針之前,給其做個備份,很好,不錯的主意,我們一般采用的方法是建立個臨時變量,這個臨時變量可以在程序循環中適當的位置使用,看下列代碼實現,是將這個臨時變量直接建立在erase實現里,這樣做更簡潔,也顯得專業些
(以刪除int型鏈表中所有偶數為例,也是大家都喜歡的一個例子):
list<int>::iterator it;
for (it = lt.begin(); it != lt.end(); ) {
if (*it % 2 == 0)
lt.erase(it++);
else
++it;
}
鏈表容器使用erase刪除節點還有一個特點,就是會將下一個元素的地址返回,所以也可以這樣實現:
list<int>::iterator it;
for (it = lt.begin(); it != lt.end(); ) {
if (*it % 2 == 0)
it = lt.erase(it);
else
++it;
}
當然用list容器本身提供的算法也是個不錯的主意(掛回調):
bool evenNumber(int n)
{
return (n % 2 == 0);
}


lt.remove_if(evenNumber);
數組容器以vector為例,當執行container.erase(it)時,和上面提到的一樣,第一個滿足條件的元素刪除了,但這時數組容器不允許中間有“空隙”,所以會做個大動作,就是將被刪元素后面所有的元素前移(參考STL源碼),而數組容器記錄的是下標,所以刪除元素后,當前下標定位的元素也就順理成章的變成了原有隊列中的下一個元素,同樣以刪除偶數為例,代碼如下:
vector<int>::iterator it = v.begin();
for (it = v.begin(); it != v.end(); ) {
if (*it % 2 == 0)
v.erase(it);
else
++it;
}
也可以使用reverse_iterator迭代器,并且在某些刪除操作中會有更好的效率(因為它會使上面提到的“大動作”變小一些):
vector<int>::reverse_iterator ri = v.rbegin();
for ( ; ri != v.rend(); ) {
if (*ri % 2 == 0)
v.erase((++ri).base());
else
++ri;
}