【问题标题】:Using std::deque::iterator (in C++ STL) for searching and deleting certain elements使用 std::deque::iterator(在 C++ STL 中)搜索和删除某些元素
【发布时间】:2013-03-07 13:55:25
【问题描述】:

我在调用以下代码时遇到了问题:

#include<deque>
using namespace std;

deque<int> deq = {0,1,2,3,4,5,6,7,8};

for(auto it = deq.begin(); it != deq.end(); it++){
    if(*it%2 == 0)
        deq.erase(it);
}

导致分段错误。在查看问题后,我发现问题在于 STL 管理双端队列迭代器的方式:如果被擦除的元素更接近双端队列的末尾,则用于指向已擦除元素的迭代器现在将指向 NEXT元素,但不是 vector::iterator 所做的前一个元素。我知道将循环条件从 it != deq.end() 修改为 it &lt; deq.end() 可能会解决问题,但我只是想知道是否有办法以“标准形式”遍历和擦除双端队列中的某些元素,以便代码可以也兼容其他容器类型。

【问题讨论】:

  • 使用std::remove_if
  • 您可以在分配给 std::remove_if 的函数(或函数对象)内执行操作,然后您仍然可以使用 std::remove_if(如@Fraser 建议的那样)。我会建议使用通用算法而不是普通循环,因为循环对您的意图不够清晰。另外,我认为同时修改和遍历容器是危险的。
  • @chris 你能提供一个deque的remove_if例子吗?我发现最后的 deque::erase(remove_if(...)) 不会删除正确的项目。 (实际上,remove_if 保持双端队列的顺序不变,但在其中放置了空格。)g++8/C++17.
  • @Daniel,您很有可能遇到了erase 的常见错误并忘记传递第二个参数,这意味着它会删除一个元素。它works here。不过,这七年后,你终于可以通过std::erase_ifdo a bit better with C++20。如果remove_if 留下“空白”,这听起来像是某种错误,无论是在实现中还是在使用中。

标签: c++ stl iterator deque


【解决方案1】:

http://en.cppreference.com/w/cpp/container/deque/erase

所有迭代器和引用都无效 [...]

返回值:最后一个被移除元素之后的迭代器。

这是从循环内的 STL 容器中删除元素时的常见模式:

for (auto i = c.begin(); i != c.end() ; /*NOTE: no incrementation of the iterator here*/) {
  if (condition)
    i = c.erase(i); // erase returns the next iterator
  else
    ++i; // otherwise increment it by yourself
}

或者正如chris 提到的,你可以使用std::remove_if

【讨论】:

    【解决方案2】:

    要使用erase-remove idiom,您需要执行以下操作:

    deq.erase(std::remove_if(deq.begin(),
                             deq.end(),
                             [](int i) { return i%2 == 0; }),
              deq.end());
    

    请务必#include &lt;algorithm&gt; 以使std::remove_if 可用。

    【讨论】:

    • 谢谢,这也是非常有用的信息!但是我有一些与要删除的元素相关的额​​外操作,所以@syam 的解决方案更适合我。无论如何谢谢!
    猜你喜欢
    • 1970-01-01
    • 2021-07-17
    • 2011-10-14
    • 2021-10-17
    • 2019-04-09
    • 2013-04-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多