删除for-range循环中项目的最快方法

The quickest method to delete items inside for - range loop

本文关键字:方法 项目 for-range 循环 删除      更新时间:2023-10-16

我在想这个循环:

struct tmp {
    int min;
    int max;
    tmp(int a, int b) :min(a), max(b){};
};
std::vector <tmp> data;
for (auto tmp_a : data){
     if(tmp_a.min == 0){
           //how to delete tmp_a item from data from there?
     }
}

当然,我可以迭代这个循环,但我不认为这是最快的方法。(当然我可能错了——那就纠正我吧)

问题:如何删除范围循环内的项目(使用最快的方法)

忘记循环并使用擦除-删除习惯用法。

data.erase(std::remove_if(data.begin(), data.end(), [] (tmp t) {
    return t.min == 0;
}), data.end());
template<class C, class F>
void remove_erase_if( C& c, F&& f ) {
  using std::begin; using std::end;
  c.erase( std::remove_if( begin(c), end(c), std::forward<F>(f) ), end(c) );
}

这是一种采用容器CCD_ 1和测试函数CCD_。它删除了所有通过测试f的元素。

我发现这样把它捆绑在一起可以减少我忘记,end(c)组件的机会,而且这两个操作(删除然后擦除)经常联系在一起,使它们成为一个操作来清理调用代码。

我们接受您的代码:

for (auto tmp_a : data){
  if(tmp_a.min == 0){
    //how to delete tmp_a item from data from there?
  }
}

并替换控制回路:

remove_erase_if( data, [&](tmp const& tmp_a){
  return (tmp_a.min == 0);
});

或在C++14:中

remove_erase_if( data, [&](auto&& tmp_a){
  return (tmp_a.min == 0);
});

其中,如果我们从lambda返回true,则元素将从容器中移除,如果我们返回false,则保留该元素。

虽然采用tmp&将进行编译,但修改tmp_a在技术上是未定义的行为。我认为这是对标准的过分规范。但是,如果您需要迭代和修改,则需要编写自己版本的remove_if:最简单的实现在修改和/或擦除元素方面没有问题。

template<class It, class F>
It my_remove_if( It start, It end, F f ) {
  It target = start;
  for(It& it = start; it != end; ++it) {
    if (f(*it))
      continue;
    if (it != target)
      *target = std::move(*it);
    ++target;
  }
  return target;
}

它与c0接口匹配(我更喜欢使用F&&,但兼容性很重要),除了它明确允许在删除元素的同时修改容器的内容之外,它也做了同样的事情。

另一种可能性是使用以下内容:

auto iter = data.begin();
while( iter != data.end() ) {
    if( iter->min == 0 )
        iter = data.erase(iter);
    else
        ++iter;
}

适用于所有容器(包括自c++11以来的关联容器),这也是erase返回迭代器的原因。如果它在clearly express intent中与擦除删除相比是好是坏,这是一个有争议的话题,我个人更喜欢它。

请注意,对于连续容器(如vector),每个erase都将移动它之后的所有项,这可能非常低效,尤其是在目标硬件没有预取功能,或者值类型不支持移动语义的情况下。

相关文章: