2017-08-18 68 views
-1

當我在class vector容器中使用erase()方法時,出現段錯誤。如何安全地擦除std :: vector中的元素

我在比較兩個向量,所以我想從其中一箇中刪除另一箇中不存在的元素。要做到這一點,我使用迭代器和erase()如下:

#include <vector> 

int main() { 

std::vector<int> vector1 {6,7,5,44,3,10,9,17,1}; 
std::vector<int> vector2 {1,2,3,5,8}; 

for (std::vector<int>::iterator it (vector2.begin()); it != vector2.end(); ++it) { 
    bool equal (false); 
    for (std::vector<int>::iterator jt (vector1.begin()); jt != vector1.end(); ++jt) { 
     if (*it == *jt) { 
      equal = true; 
      break  ; 
     } 
    } 
    if (!equal) { 
     vector2.erase(it); 
    } 
} 

return 0; 
} 

是什麼原因造成的段錯誤是最後一個元素的vector28)刪除,因爲erase()不能成功地從以前end()移動迭代器位置(不再存在)到新的位置。

這怎麼能防止?我知道unordered_set可能是適合此操作的容器,但在此我對vector感興趣。

+1

標準的方式來做到這就是所謂的[擦除刪除成語(https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom) – NathanOliver

+1

如果你真的想這樣做你嘗試這樣做的方式,我會遍歷外部循環中的vector1,以及內部循環中的vector 2。這樣你就不會從外循環中刪除矢量,並且會干擾迭代器的有效性。 – ttemple

回答

3

無法刪除,如:

if (!equal) { 
    vector2.erase(it); 
} 

erase操作無效it,所以接下來++it是錯誤的。

相反的話,你可能會改寫外循環爲:

for (std::vector<int>::iterator it (vector2.begin()); it != vector2.end();) 

,改變itfor循環中:

if (!equal) { 
    it = vector2.erase(it); 
} else { 
    ++it; 
} 

DEMO


注意,你可能會使用remove-erase idio米還有:

vector2.erase(
    std::remove_if(std::begin(vector2), std::end(vector2), [&vector1](const auto& e) { 
     return std::find(std::cbegin(vector1), std::cend(vector1), e) == std::end(vector1); 
    }), 
    std::end(vector2) 
); 

這是一個標準的方式做這樣的事情。

+0

謝謝!這解決了這個問題,現在我明白了 – EuGENE

1

問題是你的迭代器在擦除後無效。更改此:

vector2.erase(it); 

這樣:

it = vector2.erase(it); 

那將是朝着解決問題邁出的一步。檢查docs,你會發現返回值是下一個有效的迭代器。

3

正如其他人指出的那樣,問題在於擦除會使迭代器失效。但是在使用原始循環進行這種操作時,還存在一個更普遍的問題。它需要大量的樣板代碼,並且容易出錯。您可以使用標準算法來避免這些陷阱。

std::vector<int> result; 
std::sort(vector1.begin(), vector1.end()); 
std::sort(vector2.begin(), vector2.end()); 
std::set_difference(
    vector2.begin(), 
    vector2.end(), 
    vector1.begin(), 
    vector1.end(), 
    std::back_inserter(result)); 
相關問題