c++ vector刪除元素
從一個容器中刪除元素,是很常用的操作,但是也是初學者常會犯錯誤的地方,刪除map和list中元素可能會犯迭代器失效的錯誤. vector是stl裡很常用的一個容器, 和map,list等容器相比, 從vector中刪符合某些條件的元素有更多的麻煩.
比如,我們要完成如下的任務.
有下面的類
{
public:
AA():n(0){}
AA(int b):n(b){}
int n;
};
有個vector
vector
一個list
list
現在需要執行這樣的操作, 刪除vaa裡所有成員變數n在intList裡的所有元素.那麼, 應該怎麼做呢?我們可以有下列選擇:
1 手寫迴圈
仿照list的刪除方法.
for (; ite != vaa.end(); )
{
if (find(intList.begin(), intList.end(),ite->n) != intList.end())
vaa.erase(++ite);
else
++ite;
}
一執行就會發現不行了, vector的erase的特點是, 被刪除的元素和之後的所有元素的iterator都失效了, 即使儲存了後面一個iterator, 也不能繼續遍歷了. 對於這種連續儲存的序列, 應該是把不需要的元素用需要的代替, 然後把結尾不要的元素刪除.像這樣:
vector<AA>::iterator dest = ite;
for(; ite != vaa.end(); ++ite)
{
if (find(intList.begin(), intList.end(),ite->n) == intList.end())
{
*dest++ = *ite;
}
}
vaa.erase(dest, vaa.end());
2. 使用remove_if, 寫一個判斷函式作為條件.
像上面那樣寫迴圈,麻煩,容易錯而且不好讀, STL提供了一個演算法remove_if可以不用自己寫迴圈,完成上面那個迴圈的功能, 就是把不要的
元素用需要的元素代替, 返回結尾處的iterator.remove_if的原型為
ForwardIterator remove_if(ForwardIterator first, ForwardIterator last,Predicate pred);
pred是一個函式子,用來作為判斷條件. 函式子是可以按照函式呼叫的語法來使用的型別, 它可以是一個函式指標, 也可以是一個過載了operator()的型別.這裡pred要求是返回值是bool,有一個引數的函式子, 引數型別就是容器裡元素的型別, 對每個元素執行這個函式, 返回true就會被remove.
所以,我們需要先寫一個函式來判斷一個AA型別的變數是否滿足條件. 但是, 這個函式顯然需要兩個引數, 一個AA 和一個list
{
return find(lint->begin(), lint->end(), aa.n) != lint->end();
}
要把這個兩個引數的函式繫結上一個引數變成一個引數的函式, 可以使用stl裡的bind2nd函式,原型如下
binder2nd<AdaptableBinaryFunction>
bind2nd(const AdaptableBinaryFunction& F, const T& c);
這個函式並不會被執行, 編譯器只是靠它來做型別推導, 它會返回一個Adaptable unary function 型別. 它的第一個引數是一個Adaptable Binary Function, 它是一個重定義了operator()的型別,不能直接傳一個函式指標, 所以我們需要ptr_fun函式,ptr_fun對雙參函式指標的過載的原型為:
pointer_to_binary_function<Arg1, Arg2, Result>
ptr_fun(Result (*x)(Arg1, Arg2));
這個函式也是用來做型別推導的, 可以返回一個Adaptable unary function.
綜合以上各個函式, 於是就可以這樣寫了:
注意, 可能是vc6的bug, 如果inList是一個類的靜態成員函式, 上面的寫法在vc6裡無法編譯, vc6不能推匯出函式子的型別,上面的寫法在vc8和gcc中是可以的.對於vc6,需要顯式的告訴編譯器我們傳的是函式指標,像下面這樣
我們也可以讓inTheList是AA的一個成員函式
{
return find(lint->begin(), lint->end(), n) != lint->end();
}
stl提供了一套把成員函式轉為單參或雙參函式子的函式,mem_fun1_ref,這裡我們用上面的刪除操作就可以寫成:
3, 還是用remove_if, 自己定義判斷條件的函式子型別
上面那套轉換和繫結肯定能讓人抓狂, 使用函式指標來傳遞判斷條件也比較低效. 我們可以自己定義一個型別
{
public:
InListFunctor(const list<int> &lint):m_list(lint)
{}
bool operator ()(AA a)
{
return find(m_list.begin(), m_list.end(), a.n) != m_list.end();
}
private:
const list<int> &m_list;
} ;
這樣就可以直接傳給remove_if了, InListFunctor的建構函式接受一個list
通過自己定義的函式子,可以構造很複雜的比較條件,更加方便和自由.
4, 用boost::lambda, 構造匿名函式.
上面兩個方法都有個共 同的缺點, 要麼要定義一個函式, 要麼要定義一個型別, 這都會給一個類裡新增不必要的東西,這在實際程式設計中會讓人覺得不爽. 用boost::lambda可以構造匿名函式子, 不會給類的名字空間帶來汙染. 不過這個工作對boost::lambda來說有點複雜,需要包含下面三個boost::lambda標頭檔案,開啟boost::lambda的名字空 間.
#include <boost/lambda/bind.hpp>
#include <boost/lambda/algorithm.hpp>
using namespace boost::lambda;
這個刪除操作可以寫成:
vaa.end(),
bind(ll::find(),
intList.begin(),
intList.end(),(&_1)->*&AA::n)!=intList.end()),
vaa.end());
看起來有點複雜,關於boost::lambda的具體用法, 可以參考它的文件. 我一句兩句也說不清. 上式中_1是lambda的關鍵, 指的是生成的函式的第一個引數. 這裡也就是AA型別的元素.
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10697500/viewspace-526735/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- STL.vector容器刪除單個元素、部分元素、全部元素
- 建立元素和刪除元素
- jQuery刪除元素jQuery
- jQuery 刪除元素jQuery
- HashMap 之元素刪除HashMap
- JavaScript刪除陣列元素JavaScript陣列
- JavaScript 刪除陣列指定元素JavaScript陣列
- JavaScript刪除array陣列元素JavaScript陣列
- C++ vector 元素數量變化不能使用範圍 forC++
- c++ vectorC++
- vector——C++C++
- JavaScript 刪除陣列重複元素JavaScript陣列
- JavaScript 動態新增與刪除元素JavaScript
- Remove Duplicate Letters 刪除重複元素REM
- JavaScript 陣列新增或者刪除元素JavaScript陣列
- JavaScript陣列刪除重複元素JavaScript陣列
- jQuery為元素新增和刪除classjQuery
- ArrayList元素的刪除(4種函式)函式
- Python列表刪除元素的方法有哪些?Python
- 根據陣列的值刪除元素陣列
- PHP 刪除陣列中元素的方式PHP陣列
- 刪除內聯元素之間的空隙
- Array · 刪除陣列中指定的元素陣列
- JavaScript動態新增或者刪除HTML元素JavaScriptHTML
- jQuery點選按鈕刪除div元素jQuery
- jQuery刪除具有指定文字的li元素jQuery
- J2SE-刪除List集合元素
- JavaScript動態新增和刪除div元素JavaScript
- C++(std::vector)C++
- C++ Vector fundamentalC++
- C++ STL -- vectorC++
- C++:vector assignC++
- list增強for迴圈刪除元素報錯
- Python 中刪除列表元素的三種方法Python
- JavaScript刪除元素節點程式碼例項JavaScript
- PHP從陣列中刪除元素的方法PHP陣列
- C++ 順序容器的刪除操作C++
- C++簡單vectorC++
- c++ vector容器、字串C++字串