Effective STL 3 刪除特定元素

2021-07-14 22:31:24 字數 3388 閱讀 1949

rule9:在刪除選項中仔細選擇

本部分主要是講不同的容器對刪除特定元素的方法。

比如要刪除容器container< int > c中所有值為2016的物件,完成這項任務的方法因不同的容器型別而不同:沒有一種方法是通用的。

這個方法也適用於list,但是list的成員函式remove更高效。

c.remore(2016);

當c是標準關聯容器,適用任何叫做remove的方法是錯誤的,這樣的容器沒有叫做remove的成員函式,我們需要使用的適當方法是erase。 c.erase(2016);這不僅正確,而且高效,只需要花費對數時間。

接著我們考慮下面的問題,不是從c中去除每個特定值的物件,而是消除下面判斷式返回真的每個物件:

bool badvalue(int x);//返回x是否是bad

對於序列容器(vector,string,list,deque),我們需要使用remove_if。

如下**:

c.erase(remove_if(c.begin(),c.end(),badvalue),c.end());

當c是vector,string,deque時的最好方法

c.remove_if(badvalue);

當c是list時的最好方法

對於標準關聯容器,沒有提供remove_if成員函式,有兩種解決方案:

第一是容易編碼的方式,但是效率不高效,使用remove_copy_if把我們需要的值拷貝到乙個新容器中,然後把原容器的內容和新的交換。

assoccontainer< int > c;    // c現在是一種標準關聯容器                 

//goodvalues用於容納不刪除的值的臨時容器

assoccontainer< int > goodvalues;

remove_copy_if(c.begin(), c.end(), inserter(goodvalues,goodvalues.end()),badvalue);

c.swap(goodvalues);//將goodvalues的內容與c交換

我們可以通過直接從原容器刪除元素來避免上面的開銷,我們首先看如下的**:

assoccontainer c;

for (assoccontainer::iterator i = c.begin();i!= c.end();++i)

千萬不要這麼做!!!會導致程式有未定義的行為。當關聯容器的乙個元素被刪除時,指向那個元素的所有迭代器就已經失效了。當c.erase(i)返回時,i已經失效了,這樣的迴圈顯然會導致問題產生。

為了避免這個問題,我們必須保證在呼叫erase之前就得到c中下乙個元素的迭代器。使用如下的方式。

assoccontainerc;

...for (assoccontainer::iterator i = c.begin(); i != c.end();/*nothing*/ )

這種呼叫erase的解決方法可以工作,因為表示式i++的值是i的舊值,但作為***,i增加了。因此,我們把i的舊值(沒增加的)傳給erase,但在erase開始執行前i已經自增了。那正好是我們想要的。正如我所說的,**很簡單,只不過不是大多數程式設計師在第一次嘗試時想到的。

我們進一步修改該問題。不僅刪除badvalue返回真的每個元素,而且每當乙個元素被刪掉時,我們也想把一條訊息寫到日誌檔案中。

對於關聯容器,很容易,我們只需要插入寫入檔案的語句就行了。

對於vector,string和deque,我們需要使用erase的返回值,erase返回指向緊鄰被刪元素之後的元素的有效迭代器。

for (seqcontainer::iterator i = c.begin(); 

i != c.end();) // 賦給i來保持i有效

else

++i;

}

對於list結構,你可以像vector/string/deque一樣或像關聯容器一樣對待list;兩種方法都可以為list工作。

關於為什麼需要使用c.erase(remove(c.begin(),c.end(),2016),c.end())和c.erase(remove_if());這種形式來刪除特定元素?可以參見rule32:我們可以先學習這個條款。

- rule32:如果你真的想刪除東西的話,就在類似remove演算法後接上erase。

首先需要了解下 remove這個演算法的內容。remove是stl中最糊塗的演算法,容易讓人產生誤解。

remove是屬於< algorithm >演算法庫中的乙個方法,像其他的演算法一樣,remove接收指定他操作元素區間的一對迭代器,他不接受乙個容器,所以remove不知道它作用於哪個容器。此外,remove也不可能發現容器,因為沒有辦法從乙個迭代器中獲取對應的容器。

怎樣從容器中除去乙個元素呢?唯一的方法是呼叫那個容器的乙個成員函式,幾乎都是erase的某個形式。因為唯一從容器中除去乙個元素的方法是在那個容器上呼叫乙個成員函式,而且因為remove無法知道它正在操作的容器,所以remove不可能從乙個容器中除去元素,因此從乙個容器中remove元素不會改變容器中元素的個數。

如下**:

我們需要記住的就是,remove並不是真正的刪除元素,因為它做不到。

那麼remove到底做了什麼?remove移動指定區間中的元素直到所有「不刪除的」元素在區間的開頭,它返回乙個指向最後乙個的下乙個「不刪除」元素的迭代器,返回值是區間的「新邏輯終點」

vector< int > v; // 正如從前

v.erase(remove(v.begin(), v.end(), 99), v.end()); // 真的刪除所有等於99的元素

cout << v.size(); //現在返回7

把remove的返回值作為erase區間形式第乙個實參傳遞很常見,這是個慣用法。事實上,remove和erase是親密聯盟,這兩個整合到list成員函式remove中。這是stl中唯一名叫remove又能從容器中除去元素的函式:

呼叫這個remove函式是乙個stl中的矛盾。在關聯容器中類似的函式叫erase,list的remove也可以叫做erase。但它沒有,所以我們都必須習慣它。

remove不能「真的」從乙個容器中刪除東西,和erase聯合使用就變成理所當然了。你要記住的唯一其他的東西是remove不是唯一這種情況的演算法。另外有兩種「類似remove」的演算法:remove_if和unique。

linux命令 建立,刪除(3)

mkdir make directory rmdir remove directory mkdir命令用來建立新的目錄,rmdir 用來刪除已建立的目錄,這兩個指令的功能不再多加介紹,他們同dos下的md,rd功能和用法都是基本一樣的。名稱 rm 使用許可權 所有使用者 使用方式 rm option...

C this指標 3 刪除this指標

通常通常情況下,delete操作符不應該用於刪除this指標。但是,一旦使用了delete this,則需要考慮到下面的這些情況。1 delete操作符只允許與使用new分配的物件配套使用 如果物件是用new建立的,則可以使用delete this,否則會導致未知的行為。具體可參考本人之前的這篇文章...

3 級聯刪除

authors表是主表 books表是子表 預設情況下,當使用datacontext.dbset.remove 刪除authors時,與之相關的books也會一起刪除掉.using var context new bookstore 不過可以使用willcascadeondelete false 來...