一起来学习C++中remove与erase的理解
erase 简介
vector
中 erase
函数原型如下:
iterator erase( const_iterator position); iterator erase( const_iterator first, const_iterator last);
用于删除 vector 容器中的一个或者一段元素。
在删除一个元素的时候,其参数为指向相应元素的迭代器;而在删除一段元素的时候,参数为指向一段元素的开头的迭代器以及指向结尾元素的下一个元素的迭代器。
调用 erase
后,vector
元素会向前移,因此需要格外注意这个特征,避免越界访问以及漏处理。
示例代码:
int main(int argc, char *argv[]) { vector<int> myVector; myVector.push_back(1); myVector.push_back(2); myVector.push_back(3); myVector.push_back(3); myVector.push_back(3); myVector.push_back(4); myVector.push_back(3); myVector.push_back(3); myVector.push_back(3); for (vector<int>::iterator itr = myVector.begin(); itr != myVector.end(); itr++) { if (*itr == 3) { //此时itr已经指向了新的下一个元素;如果不执行itr--与itr++做抵消,则会超出end导致崩溃。 itr = myVector.erase(itr); itr--; } } cout << "[After erase] myVector: "; for (int temp : myVector) cout << temp << " "; cout << endl; return 0; }
remove 简介
algorithm
中 remove
原型如下:
template<class ForwardIterator, class Type> ForwardIterator remove( ForwardIterator first, ForwardIterator last, const Type& value); template<class ExecutionPolicy, class ForwardIterator, class Type> ForwardIterator remove( ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, const Type& value);
remove
函数是由 STL
库中 algorithm
提供的一个函数,这里的 remove
字面意思很容易引起初学者误解。因为调用以后并非真实的 remove
。
代码示例
#include <vector> #include <iostream> #include <algorithm> using namespace std; int main(int argc, char *argv[]) { vector<int> array; array.push_back(1); array.push_back(2); array.push_back(3); array.push_back(3); array.push_back(4); array.push_back(5); cout << "init : "; print(array); array.erase(array.begin()); cout << "erase array.begin() :"; print(array); vector<int>::iterator remove2It = remove(array.begin(), array.end(), 2); cout << "remove 2 : "; print(array); cout << "remove2It traverse : "; for (; remove2It != array.end(); remove2It++) cout << *remove2It << " "; cout << endl; vector<int>::iterator remove3It = remove(array.begin(), array.end(), 3); cout << "remove 3 : "; print(array); cout << "remove3It traverse : "; for (; remove3It != array.end(); remove3It++) cout << *remove3It << " "; cout << endl; return 0; }
运行后打印如下:
init : 1 2 3 3 4 5
erase array.begin() :2 3 3 4 5
remove 2 : 3 3 4 5 5
remove2It traverse : 5
remove 3 : 4 5 5 5 5
remove3It traverse : 5 5
代码分析
如上所示,执行 array.erase(array.begin());
后,符合预期地将第一个元素删除了,打印结果为:erase array.begin() : 2 3 3 4 5
。
在此基础(2 3 3 4 5
)上执行 remove(array.begin(), array.end(), 2);
,可能惯性思维会觉得得到的结果(这个是错误的结果,效果就像调用了 erase 一样)应该是 3 3 4 5
,4 个元素。而实际打印结果为:3 3 4 5 5
,5 个元素。这里完全“颠覆”了对 remove 这一字义的认识。
remove 是如何工作的?
查找资料后发现,remove
和 erase
存在很大的区别。
remove
是 algorithm
的模板函数,它接收的都是迭代器参数,并不接收某个容器。remove
并不知道它作用于哪个容器,也不可能发现容器,因为没有办法从一个迭代器获得对应于它的容器。
想要从容器中删除一个元素,唯一的方法就是调用容器的一个成员函数,比如 erase
函数。而 remove
无法知晓,故不可能根据一个传进来的迭代器进而在该容器中除去元素。因此,调用 remove
后并不会改变该容器的元素个数。
得出的结论是:remove
并不是真的在删除元素,因为它根本做不到。
remove 的工作流程
(注意:begin
与 end
是左闭右开区间,即 end
是 vector
之外了,即 vector
最后一个元素的下一个。)
这里需要明确一点是,remove()
的返回值是一个 iterator
。
再来看 remove(3) 的过程:
至此,大概可以弄清楚 remove
这个函数对一个 vector
做了哪些操作,改变了哪些元素的顺序,以及返回值是指向何处。