2017-01-25 52 views
3

我遇到了一個問題,我想通過我的矢量並刪除不再需要的元素。爲什麼它失敗的原因很明顯,但當我嘗試我的天真方法時,我沒有看到它。基本上,當我擦除一個元素時迭代器失效,並且循環無法繼續。我所做的是以下幾點:什麼是遍歷矢量和刪除某些元素的正確方法

#define GOOD 1 
    #define BAD 0 

    struct Element 
    { 
     Element(int isGood) : good(isGood){} 
     bool good; 
    }; 

    int main() 
    { 
     std::vector<Element> arr; 
     arr.push_back(Element(BAD)); 
     arr.push_back(Element(GOOD)); 
     arr.push_back(Element(BAD)); 
     arr.push_back(Element(GOOD)); 

    //__CLEAN ARRAY__// 
     for (auto it = arr.begin(); it != arr.end(); ++it) 
     { 
      if ((*it).good == false) arr.erase(it); 
     } 
    } 

所以,很明顯,這是不行的,我想知道這樣做的正確的/最好的辦法是。我的下一步將是重新啓動循環,如果沒有找到好的迭代器,但這也看起來很浪費。理想情況下,循環會繼續使用新的迭代器停止。

謝謝。

+3

閱讀關於'std :: remove_if'。 –

回答

3

你想:

arr.erase(std::remove_if(arr.begin(), arr.end(), [](auto& obj){return obj.good == false;}), arr.end()); 

和其所謂的刪除擦除成語:

https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom

但是,如果你要修復環路,則有可能,擦除返回一個有效的迭代器,所以你應該使用它:

for (auto it = arr.begin(); it != arr.end();) 
    { 
     if ((*it).good == false) 
     it = arr.erase(it); 
     else 
     it++; 
    } 
+0

謝謝。我只是想說remove和remove_if不要調整容器的大小。因此,如果我有10個元素,並刪除2,則迭代器會在8個元素的末尾返回新的結尾,但是container.end()迭代器仍然指向結尾處的結尾10 + 1。那麼這個矢量容器就沒用了,不是嗎?此外,這是否會影響循環的優化機會,因爲它必須重新檢查arr.end()每個循環迭代。 – Zebrafish

+0

std :: remove_if返回vector的新end(),arr.erase使用它刪除所有已移除的元素。所以在執行這個語句之後,arr將會有8個元素。我不確定我是否理解你的第二個問題,如果你使用循環,那麼你肯定需要在每次迭代時檢查.end()。 – marcinj

+0

哦,我明白了,你的意思是在remove_if之後在範圍上調用擦除。我提到的第二件事是,如果編譯器知道它不會改變,迭代器就不必每次檢查。這不是編譯器的優化之一嗎? – Zebrafish