删除范围循环中项目的最快方法

时间:2015-03-24 23:08:08

标签: c++ c++11

我在考虑这个循环:

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?
     }
}

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

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

3 个答案:

答案 0 :(得分:8)

放弃循环并使用擦除 - 删除习惯用法。

data.erase(std::remove_if(data.begin(), data.end(), [] (tmp t) {
    return t.min == 0;
}), data.end());

答案 1 :(得分:1)

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

这是一个采用容器c和测试函数f的算法。它会删除通过测试的所有元素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;
}

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

答案 2 :(得分:-1)

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

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都会移动后面的所有项目,这可能效率很低,尤其是当目标硬件没有预先设置时提取或值类型不支持移动语义。