怎麼從vector裡刪除元素

2021-04-12 15:49:10 字數 4049 閱讀 1065

現在用stl的人越來越多, stl確實是套很漂亮的演算法和資料結構庫. 但是初用stl的人往往會遇上很多問題.

從乙個容器中刪除元素,是很常用的操作,但是也是初學者常會犯錯誤的地方,刪除map和list中元素可能會犯迭代器失效的錯誤. vector是stl裡很常用的乙個容器, 和map,list等容器相比, 從vector中刪符合某些條件的元素有更多的麻煩.

比如,我們要完成如下的任務.

有下面的類

class

aaaa(

intb):n(b){}

intn;};

有個vector

vectorvaa;

乙個list

listintlist;

現在需要執行這樣的操作, 刪除vaa裡所有成員變數n在intlist裡的所有元素.那麼, 應該怎麼做呢?我們可以有下列選擇:

1 手寫迴圈

仿照list的刪除方法.

vector

<

aa>

::iterator ite 

=vaa.begin();

for(; ite 

!=vaa.end(); )

一執行就會發現不行了, vector的erase的特點是, 被刪除的元素和之後的所有元素的iterator都失效了, 即使儲存了後面乙個iterator, 也不能繼續遍歷了. 對於這種連續儲存的序列, 應該是把不需要的元素用需要的代替, 然後把結尾不要的元素刪除.像這樣:

vector

<

aa>

::iterator ite 

=vaa.begin();

vector

<

aa>

::iterator dest 

=ite;

for(; ite 

!=vaa.end(); 

++ite)

}vaa.erase(dest, vaa.end());

2. 使用remove_if, 寫乙個判斷函式作為條件.

像上面那樣寫迴圈,麻煩,容易錯而且不好讀, stl提供了乙個演算法remove_if可以不用自己寫迴圈,完成上面那個迴圈的功能, 就是把不要的

元素用需要的元素代替, 返回結尾處的iterator.remove_if的原型為

template 

<

class

forwarditerator, 

class

predicate

>

forwarditerator remove_if(forwarditerator first, forwarditerator last,predicate pred);

pred是乙個函式子,用來作為判斷條件. 函式子是可以按照函式呼叫的語法來使用的型別, 它可以是乙個函式指標, 也可以是乙個過載了operator()的型別.這裡pred要求是返回值是bool,有乙個引數的函式子, 引數型別就是容器裡元素的型別, 對每個元素執行這個函式, 返回true就會被remove.

所以,我們需要先寫乙個函式來判斷乙個aa型別的變數是否滿足條件. 但是, 這個函式顯然需要兩個引數, 乙個aa 和乙個list,為了避免拷貝,我們用指標傳遞list

bool

inthelist( aa aa, 

const

list

<

int>

*lint)

要把這個兩個引數的函式繫結上乙個引數變成乙個引數的函式, 可以使用stl裡的bind2nd函式,原型如下

template 

<

class

adaptablebinaryfunction, 

class

t>

binder2nd

<

adaptablebinaryfunction

>

bind2nd(

const

adaptablebinaryfunction

&f, 

constt&

c);

這個函式並不會被執行, 編譯器只是靠它來做型別推導, 它會返回乙個adaptable unary function 型別. 它的第乙個引數是乙個adaptable binary function, 它是乙個重定義了operator()的型別,不能直接傳乙個函式指標, 所以我們需要ptr_fun函式,ptr_fun對雙參函式指標的過載的原型為:

template 

<

class

arg1, 

class

arg2, 

class

result

>

pointer_to_binary_function

<

arg1, arg2, result

>

ptr_fun(result (

*x)(arg1, arg2));

這個函式也是用來做型別推導的, 可以返回乙個adaptable unary function.

綜合以上各個函式, 於是就可以這樣寫了:

vaa.erase(remove_if(vaa.begin(), vaa.end(),bind2nd(ptr_fun(inthelist),

&intlist)), vaa.end());

注意, 可能是vc6的bug, 如果inlist是乙個類的靜態成員函式, 上面的寫法在vc6裡無法編譯, vc6不能推導出函式子的型別,上面的寫法在vc8和gcc中是可以的.對於vc6,需要顯式的告訴編譯器我們傳的是函式指標,像下面這樣

vaa.erase(remove_if(vaa.begin(), vaa.end(),bind2nd(ptr_fun(

&inthelist),

&intlist)), vaa.end());

我們也可以讓inthelist是aa的乙個成員函式

bool

aa::inthelist(

const

list

<

int>

*lint)

stl提供了一套把成員函式轉為單參或雙參函式子的函式,mem_fun1_ref,這裡我們用上面的刪除操作就可以寫成:

vaa.erase(remove_if(vaa.begin(), vaa.end(),bind2nd(mem_fun1_ref(

&aa::inthelist),

&intlist)), vaa.end());

3, 還是用remove_if, 自己定義判斷條件的函式子型別

上面那套轉換和繫結肯定能讓人抓狂, 使用函式指標來傳遞判斷條件也比較低效. 我們可以自己定義乙個型別

class

inlistfunctor

bool

operator

()(aa a)

private

:const

list

<

int>

&m_list;

} ;

這樣就可以直接傳給remove_if了, inlistfunctor的建構函式接受乙個list的const引用, 可以把要比較的list傳進去.

vaa.erase(remove_if(vaa.begin(), vaa.end(), inlistfunctor(intlist)), vaa.end());

通過自己定義的函式子,可以構造很複雜的比較條件,更加方便和自由.

4, 用boost::lambda, 構造匿名函式.

上面兩個方法都有個共同的缺點, 要麼要定義乙個函式, 要麼要定義乙個型別, 這都會給乙個類裡新增不必要的東西,這在實際程式設計中會讓人覺得不爽.

c++0x

裡面提供了

lambda

,可以構造匿名函式。這個特性已經在

vs2010

裡面實現了。於是可以用下面的**來實現刪除。

vaa.erase(remove_if(vaa.begin(), vaa.end(),

[&intlist](const aa &a)),

vaa.end());

關於lambda的具體語法,可以參看這裡 http://msdn.microsoft.com/en-us/library/dd293608.aspx

怎麼從vector裡刪除元素

現在用stl的人越來越多,stl確實是套很漂亮的演算法和資料結構庫.但是初用stl的人往往會遇上很多問題.從乙個容器中刪除元素,是很常用的操作,但是也是初學者常會犯錯誤的地方,刪除map和list中元素可能會犯迭代器失效的錯誤.vector是stl裡很常用的乙個容器,和map,list等容器相比,從...

Vector容器刪除元素

使用vector容器也有一段時間了,但是對於他的刪除操作還是有點疑問,今天就總結一下。vector資料儲存是一段預先分配好大小的記憶體連續的空間,插入資料和刪除資料都會引起後面資料記憶體的整體移動。今天就說說刪除操作吧 1 刪除最後的元素 直接使用pop back 就可以了,這個沒什麼好說的 2 刪...

vector 之刪除元素

刪除指定位置的元素 刪除vector中第5個位置的元素 1 vector vec 執行vector初始化操作 2 vector iterator iter vec.begin 5 獲取第五個元素的iterator 3 vec.erase iter 刪除第五個元素 刪除重複元素 刪除vector中的重...