通过迭代器从std::vector中删除

Remove by iterator from std::vector

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

为了从std::vector中删除迭代器,我可以做以下两件事:

std::vector<int>& vec = myNumbers; // use shorter name
vec.erase(std::remove(vec.begin(), vec.end(), number_in), vec.end());

或者我可以这样做:

auto it = find(vec.begin(), vec.end(), number_in);
vec.erase(it);

第二个更直观,我想,但哪一个更快?

编辑:向量中的元素是唯一的,我们不必担心一次删除几个元素

第一个版本可以保证正常工作,而第二个版本可能会更快(因为std::find会停在第一个匹配的项目上),但肯定不会更安全。

auto it = find(vec.begin(), vec.end(), number_in);
if (it != vec.end())
   vec.erase(it);

这将确保您不会擦除无效的迭代器。

所以这取决于你的需求。如果你想要一个正确的程序,第一个程序可以在没有进一步干预的情况下运行,但第二个程序需要你的客户提供错误通知单,然后你必须去修复它(如上所述)。

第二个更快-第一个会试图找到所有等于number_in的元素,尽管它已经找到了一个。然而,第二个会在找到一个时停止。

std::vector::erase

  • 移除位置的元件

  • 删除范围[first;last]中的元素。

    使擦除点处或之后的迭代器和引用无效,包括end()迭代器。迭代器位置必须有效且可取消引用。因此,end()迭代器(有效,但不可取消引用)不能用作pos的值。如果first==last,则迭代器first不需要是可取消引用的:擦除空范围是不可行的。

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

第一种方法将较慢,因为将搜索整个向量以查找数字。但这也是一种更安全的方式。假设number_in不是向量的元素。第一种方法是尝试擦除一个已定义且安全的空范围。第二种方法是尝试删除向量的结束迭代器,这是不安全的,也是UB。

您似乎对性能感兴趣。查找(第一个)匹配元素的速度不能比O(n)快。因此,您可以尝试提高性能的部分是删除,它可以是O(1)如果允许向量元素的改变顺序。例如

// find requires up to O(n)
auto it = std::find(v.begin(),v.end(),value);
// remove in O(1) but don't preserve order
if(it!=v.end()) {
  std::iter_swap(it,--(v.end()));
  v.pop_back();
}

注意,使用std::remove()和/或vector::erase()的解决方案将保留剩余元素的顺序,因此不可避免的仍然压缩剩余元素(引用自Tony D的评论),这几乎总是比找到匹配元素更昂贵,因此主导了计算成本。

试试哪种解决方案更快——布丁的证据就在吃!