使用迭代器从“查找”或“删除”中删除

问题描述 投票:0回答:2

我想知道在 C++ 中从向量中删除元素的最佳实践是什么。

我见过很多次人们使用 std::remove 来查找并删除元素,然后使用擦除从向量中删除元素。

但是为什么它比使用 find 获取要删除的元素的迭代器然后使用该迭代器进行擦除更好呢?

谢谢

c++ vector std
2个回答
25
投票

std::find
后跟
vector::erase
将从
vector
中删除第一次出现的具有给定值的对象。

std::vector<int> vec{1,3,3,8,3,5};
vec.erase(std::find(vec.begin(), vec.end(), 3));
//vec == {1,3,8,3,5}

std::remove
后跟
vector::erase
将从 vector 中删除
每一个
具有给定值的对象。

std::vector<int> vec{1,3,3,8,3,5};
vec.erase(std::remove(vec.begin(), vec.end(), 3), vec.end());
//vec == {1,8,5}

没有更好,他们只是做不同的事情。

std::remove
更普遍有用,这就是为什么它更常见;特别是,当向量中不存在元素时,
std::remove
后跟
vector::erase
不执行任何操作,而
std::find
后跟
vector::erase
具有未定义的行为。

请注意,“查找-擦除”、“删除-擦除”都保持元素的相对顺序。如果你想从向量中删除一个元素,但不关心元素的结果顺序,你可以使用“find-move-pop_back”或“partition-erase”:

//find-move-pop_back
std::vector<int> vec{1,3,3,8,3,5};
*std::find(vec.begin(), vec.end(), 3) = std::move(vec.back());
vec.pop_back();

//partition-erase
std::vector<int> vec{1,3,3,8,3,5};
vec.erase(
    std::partition(vec.begin(), vec.end(), [](int v){return v != 3;}),
    vec.end());

0
投票

你是对的,

std::erase
std::remove
只是返回一个迭代器。但
std::remove
做了一件事不同:它首先将要删除的元素移动到向量的末尾。然后你打算从元素
std::erase
调用
std::remove
返回,到向量的末尾。

您可以使用该属性来找出从 std::vector 中删除了多少元素:


void print( vector<string> &v ) {
  for( auto&& s : v ) {
    printf( "  - %s\n", s.c_str() );
  }
  puts("");
}

int main() {
  
  vector<string> s = { "Strings", "a", "in", "a", "a", "a", "test", "test", "a", "a", "vector" } ;
  puts( "Original" );
  print( s );

  auto it = std::remove( s.begin(), s.end(), "a" );
  printf( "Deleting %d elts\n", s.end() - it );
  s.erase( it, s.end() );

  puts( "After" );
  print( s );

}

© www.soinside.com 2019 - 2024. All rights reserved.