Erase–remove惯用法
动机
一个常见的编程任务是从集合(collection)中删除等于某个值或满足某个标准的所有元素。C++语言可以通过手写循环完成这个任务。但更好的办法是使用C++标准模板库中的算法来实现。[1][2][3]
erase
用于从一个集合中删除一个元素,但是对于基于数组的容器,如vector
,存储在被删除元素后的所有元素都需要向前移動以避免集合中有一个空位(gap)。在同一容器中多次调用产生了大量移动元素的开销。
algorithm
库提供了remove
与remove_if
算法。由于这些算法运行在两个前向迭代器确定的元素范围上,它们没有底层容器或集合的具体知识。[1][4]这些算法并不从容器删除元素,而是把不“符合”删除标准的元素搬移到容器的前部,并保持这些元素的相对次序。该算法一次通过数据范围即可实现该目标。
由于没有元素被删除,因此容器尺寸保持不变。容器尾部的元素都是需要被删除的,但其状态未指定(unspecified state)。remove
返回一个迭代器指向尾部这些需要用erase
删除的元素的第一个。
同样的事情(删除多个元素),用容器的方法erase
会导致多次遍历这个容器,每一次遍历时,在被删除元素之后的所有元素都必须向前移动,其时间消耗远大于单次通过。
局限
erase–remove惯用法不能用于返回const_iterator
(例如:set)[5]的容器。
std::remove
与std::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
*/
参考文献
- Meyers, Scott. . Addison-Wesley. 2001.
- Sutter, Herb; Alexandrescu, Andrei. . Addison-Wesley. 2004.
- C/C++ Users Journal, October 2001. STL Algorithms vs. Hand-Written Loops (页面存档备份,存于)
- Josuttis, Nicolai. . Addison-Wesley. 1999.
- . [14 April 2013].
- Meyers, Scott. . Boston: Addison-Wesley. 2001: 143–145. ISBN 0201749629. OCLC 46713127.
This article is issued from Wikipedia. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.