2017-01-25 37 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