【问题标题】:What's the correct way to iterate through a vector and delete certain elements [duplicate]遍历向量并删除某些元素的正确方法是什么[重复]
【发布时间】:2017-06-11 06:33:00
【问题描述】:

我遇到了一个问题,我想遍历我的向量并删除不再需要的元素。它失败的原因很明显,但是当我尝试我的幼稚方法时并没有看到它。基本上,当我删除一个元素时,迭代器会失效,并且循环无法继续。我所做的如下:

    #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);
        }
    }

所以很明显这不起作用,我想知道这样做的正确/最佳方法是什么。如果没有找到好的,我的下一步是用新的迭代器重新启动循环,但这似乎也是一种浪费。理想情况下,循环会在它停止的地方继续使用新的迭代器?

谢谢。

【问题讨论】:

  • 了解std::remove_if

标签: c++ arrays loops vector iterator


【解决方案1】:

你想要:

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

及其所谓的remove-erase idiom:

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

但是如果你想修复循环那么它是可能的,erase 返回下一个有效的迭代器,所以你应该使用它:

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

【讨论】:

  • 谢谢。我只是想说 remove 和 remove_if 不要调整容器的大小。因此,如果我有 10 个元素并删除 2 个元素,则迭代器会在 8 个元素的末尾返回新的结尾,但 container.end() 迭代器仍然指向结尾的一个,即 10 + 1。这种使得在此之后,矢量容器就没用了,不是吗?此外,这是否会影响循环的优化机会,因为它必须在每次循环迭代时重新检查 arr.end()。
  • std::remove_if 返回向量的新 end() ,并且 arr.erase 使用它来删除所有已删除的元素。所以这条语句执行后,arr 将有 8 个元素。我不确定我是否理解您的第二个问题,如果您使用循环,那么您肯定需要在每次迭代时检查 .end()。
  • 哦,我明白了,您的意思是在执行 remove_if 之后在范围上调用擦除。我提到的第二件事的意思是,如果编译器知道迭代器不会改变,就不必每次都检查迭代器。这不是编译器所做的优化之一吗?
猜你喜欢
  • 1970-01-01
  • 2014-04-12
  • 2012-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-31
  • 2022-01-21
相关资源
最近更新 更多