通过反向迭代器从矢量快速删除

fast deletion from vector with a reverse iterator

本文关键字:删除 迭代器      更新时间:2023-10-16

我想删除符合某些条件的向量入口,呼叫它们的函数。我不在乎稳定的订购,所以通常我实际上会移动最终数组元素来替换正在检查的元素。

问题:用迭代器做到这一点的最光滑的习语是什么?

(是的,如果您想保留订购,则擦除是标准的成语,但是就我而言,这是不需要的,我认为由于这些动作而比我在这里给出的版本要慢。(

(

使用int下标,我会这样做,并且此代码有效:

  for ( int i = (int) apc.size() - 1; i >= 0; i-- )
      if ( apc[i]->blah ) {
          MyFunc( apc[i] );
          apc[i] = apc.back();
          apc.pop_back();
      }

我尝试使用反向迭代器进行相同的操作,并且在第一次进入IF块后,它会在for循环的 中吹来。我不知道为什么。如果实际上是在 *上调用erase(( *,我知道这会使它变得不确定,但我不是这样做。我想pop_back((将不确定rbegin((。我应该检查它是否进入第一次迭代时的IF块,并且是否仅在这种情况下崩溃。

  for ( auto it = apc.rbegin(); it != apc.rend(); it++ )
      if ( (*it)->blah ) {
          MyFunc( *it );
          *it = apc.back();
          apc.pop_back();
      }

在前进迭代器中,它似乎可以正常工作,尽管我不喜欢在以blah true找到元素时停止循环的切口效果。反向环有点丑

  for ( auto it = apc.begin(); it != apc.end(); )
      if ( (*it)->blah ) {
          MyFunc( *it );
          *it = apc.back();
          apc.pop_back();
      } else
          it++;

pop_back通常只应仅使back()end()无效。但是,如果必须删除数组的最后一个元素,则可以被角案抓住。对于索引,没问题,您会尝试在本身上移动一个元素,这应该是一个no-op,然后在先前的索引上进行。但是使用迭代器,当前值是back(),因此应无效。

提防,这在您的实施中也可能是一个问题,因此提供该信息可能是有意义的,以便其他人可以尝试使用此或其他实现来复制。

我认为旧且经过测试的擦除式成语很好地覆盖了。

apc.erase(std::remove_if(apc.begin(), apc.end(), [](auto& v) {
    if (v->blah) {
        MyFunc(v);
        return true;
    }
    return false;
}), apc.end());

这个习语将所有要删除的元素移至std::remove_if的末端,然后我们将所有元素与erase一起删除。

编辑:正如马歇尔指出的那样,该算法将将要保持在正面的元素将其移动到前面,这是有意义的,考虑到它承诺保留保留元素的相对排序。p>如果lambda需要在this或其他任何变量上作用,则需要捕获v中传递的。在这种情况下,我们不必担心寿命,因此默认捕获是一个不错的选择。

[&](auto& v) {
    if (v->blah < x) { //captures x by reference
        MyFunc(v, member_variable); //current object is captured by reference, and can access member variables
        return true;
    }
    return false;
})

如果MyFunc可能可以修改member_variable,我们还需要使Lambda可变。

默认情况下,lambda使用operator() const创建一个功能对象,但mutable删除了const

[&](auto& v) mutable { ... }