Erase–remove惯用法

Erase–remove惯用法'C++程序设计语言常用的技术,用于在C++标准模板库容器中删除元素。[1][2][3]

动机

编辑

一个常见的编程任务是从集合(collection)中删除等于某个值或满足某个标准的所有元素。C++语言可以通过手写循环完成这个任务。但更好的办法是使用C++标准模板库中的算法来实现。[1][2][3]

erase用于从一个集合中删除一个元素,但是对于基于数组的容器,如vector,存储在被删除元素后的所有元素都需要向前移动以避免集合中有一个空位(gap)。在同一容器中多次调用产生了大量移动元素的开销。

algorithm库提供了removeremove_if算法。由于这些算法运行在两个前向迭代器确定的元素范围上,它们没有底层容器或集合的具体知识。[1][4]这些算法并不从容器删除元素,而是把不“符合”删除标准的元素搬移到容器的前部,并保持这些元素的相对次序。该算法一次通过数据范围即可实现该目标。

由于没有元素被删除,因此容器尺寸保持不变。容器尾部的元素都是需要被删除的,但其状态未指定(unspecified state)。remove返回一个迭代器指向尾部这些需要用erase删除的元素的第一个。

同样的事情(删除多个元素),用容器的方法erase会导致多次遍历这个容器,每一次遍历时,在被删除元素之后的所有元素都必须向前移动,其时间消耗远大于单次通过。

局限

编辑

erase–remove惯用法不能用于返回const_iterator (例如:set[5]的容器。

std::removestd::remove_if不能保持被删除的元素(不像std::partition, std::stable_partition)。因此,erase–remove只能用于容器的元素是全值语义不会招致资源泄露。[6]

例子

编辑
// Use g++ -std=c++11 or clang++ -std=c++11 to compile.

#include <algorithm>  // remove and remove_if
#include <iostream>
#include <vector>  // the general-purpose vector container

bool IsOdd(int i) { return i & 1; }

void Print(const std::vector<int>& vec) {
  for (const auto& i : vec) {
    std::cout << i << ' ';
  }
  std::cout << std::endl;
}

int main() {
  // Initializes a vector that holds numbers from 0-9.
  std::vector<int> v = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
  Print(v);

  // Removes all elements with the value 5.
  v.erase(std::remove(v.begin(), v.end(), 5), v.end());
  Print(v);

  // Removes all odd numbers.
  v.erase(std::remove_if(v.begin(), v.end(), IsOdd), v.end());
  Print(v);
}

/*
Output:
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 6 7 8 9
0 2 4 6 8
*/

参考文献

编辑
  1. ^ 1.0 1.1 1.2 Meyers, Scott. Effective STL: 50 Specific Ways to Improve Your Use of the Standard Template Library. Addison-Wesley. 2001. 
  2. ^ 2.0 2.1 Sutter, Herb; Alexandrescu, Andrei. C++ Coding Standards: 101 Rules, Guidelines, and Best Practices. Addison-Wesley. 2004. 
  3. ^ 3.0 3.1 C/C++ Users Journal, October 2001. STL Algorithms vs. Hand-Written Loops页面存档备份,存于互联网档案馆
  4. ^ Josuttis, Nicolai. C++ Standard Library – A Tutorial and Reference. Addison-Wesley. 1999. 
  5. ^ Erase–remove idiom with std::set. [14 April 2013]. 
  6. ^ Meyers, Scott. Effective STL : 50 specific ways to improve your use of the standard template library . Boston: Addison-Wesley. 2001: 143–145. ISBN 0201749629. OCLC 46713127.