2013-11-15 64 views
4

假設您想通過值從矢量中刪除單個元素。是什麼remove -erase之間的區別:刪除 - 刪除和查找 - 刪除有什麼區別

vector<int> v; 
// add some values 
vector<int>::iterator it = remove(v.begin(), v.end(), 5); 
v.erase(it); 

和查找刪除

vector<int> v; 
// add some values 
vector<int>::iterator it = find(v.begin(), v.end(), 5); 
if(it != v.end()) 
{ 
    v.erase(it); 
} 
+0

[我在這裏做了兩個評論,但他們都錯了,請忽略:-)] –

+0

更好的答案在這裏提供:https://stackoverflow.com/questions/24011627/erasing-using-iterator-from-查找或刪除 – giuseppe

回答

13

您的刪除代碼不正確。刪除擦除成語看起來像這樣:

vector<int>::iterator it = remove(v.begin(), v.end(), 5); 
v.erase(it, v.end()); 

在這種情況下,它具有擦除等於5的所有值的效果,但是它最小化拷貝以實現所需的量。

您的查找 - 刪除代碼只會刪除第一個等於5的值,因此它會按照您的要求進行操作。

刪除代碼將所有不等於5的值移動到向量的前面(這就是std::remove的作用),擦除向量的剩餘元素之一,並在其後留下任何其餘元素,其中包含未指定的值(這也是remove所做的)。如果矢量首先不包含5,則它具有未定義的行爲,因爲在這種情況下,remove將返回v.end()

因此,如果您只想擦除幾個等於5的單個元素,那麼std::remove對您沒有用處,因爲它不保留(其他)5。如果你想在非5值開始和5個值移動到結束,去除第一的5S之前,那麼你實際上可以做到這一點與std::partition只是不能與std::remove

auto it = partition(v.begin(), v.end(), [](int i) { return i != 5; }); 
if (it != v.end()) v.erase(it); 

雖然,因爲一個5作爲另一個您刪除了最後的5秒,而不是第一個獲得相同的結果,而且它的效率更高,當有超過其中一個是好的:

auto it = partition(v.begin(), v.end(), [](int i) { return i != 5; }); 
if (it != v.end()) v.pop_back(); 

如果你能以某種方式確保矢量最初包含正好一個元素等於5(沒有更多或更少s),那麼你的兩個代碼就會做同樣的事情。在這種情況下,您不需要在查找 - 清除代碼中對it != v.end()進行測試,您會知道它不相同。你可以做v.erase(find(v.begin(), v.end(), 5))

+0

時,你們太快了,很好的提到了標準的擦除習慣用法;但OP實際上只是**希望**刪除**一個**發生 – codeling

1

所不同的是,如果有多個值匹配給定之一,remove解決方案將所有移動的非匹配項目的開始(感謝Steve Jessop在評論中指出)。然後只有erase將刪除這些的第一次發生;最後得到一個重新排序的vector,其中包含一個給定值。

find - 解決方案只會刪除第一次發生,而不會改變向量的順序。

+0

'remove'不會將相等的值移動到末尾,它會將不相等的值移動到開頭。最後剩下的是未指定的。 –

-1

您是否真的嘗試瞭解區別?

在第一代碼段,std::remove通過將所有中等於5到載體的端部的元件變換向量,並返回迭代器端。當你打電話給erase時,你會在新的結束後刪除第一個元素。你可能想要做的:

vector<int>::iterator it = remove(v.begin(), v.end(), 5); 
v.erase(it, v.end()); 

這將刪除所有與價值5

元素在第二個例子,std::find發現等於5向量的第一個元素,並返回一個迭代器它。調用erase只會刪除該元素。

這是區別。

+0

他稱之爲擦除的單參數版本,因此只有一個元素被擦除。 –

+0

在第一段代碼中調用'erase'將只擦除第一個被刪除的元素。 – Snps

+0

是的,我注意到,但是當我編輯我的回答 –