如果你真的想删除东西的话就在类似remove的算法后接上 erase
要特别注意标准库的remove的函数它的实现。
这是remove的声明:
template<class ForwardIterator, class T>
ForwardIterator remove(ForwardIterator first, ForwardIterator last,
const T& value);
就像所有算法,remove接收指定它操作的元素区间的一对迭代器。它不接收一个容器,所以remove不知道它作用于哪个容器。此外,remove也不可能发现容器,因为没有办法从一个迭代器获取对应于它的容器。
想想怎么从容器中除去一个元素。唯一的方法是调用那个容器的一个成员函数,几乎都是erase的某个形式,(list有几个除去元素的成员函数不叫erase,但它们仍然是成员函数。)因为唯一从容器中除去一个元素的方
法是在那个容器上调用一个成员函数,而且因为remove无法知道它正在操作的容器,所以remove不可能从一个容器中除去元素。这解释了另一个令人沮丧的观点——从一个容器中remove元素不会改变容器中元素的个数。
所以可以尝试以下代码:
vector<int> vec = { 1,1,2,2,3,3,4,4,5,6 };
cout << "Size:" << vec.size() << endl; //print
std::remove(vec.begin(), vec.end(), 3);
for (auto item : vec)
{
cout << " item:" << item << endl;
}
cout << "Size:" << vec.size() << endl; //print
从打印可以看出容器的大小完全没有改变见下图,
我们可以看出容器大小没变化,但是最后两个元素时5和6,这里我们解释一下为什么会出现这种情况:
- remove检测v[0],发现它的值不是要被删除的,然后移动到v[1]。同样的情况发生在v[1]和v[2]。
- 发现v[3]应该被删除,所以它记录下v[3]的值应该被覆盖,然后它移动到v[4]。这类似记录v[3]是一个需要填充的“洞”。
- 发现v[4]的值应该被保持,所以它把v[4]赋给v[3],记录下v[4]应该被覆盖,然后移动到v[5]。继续类似的压缩,它用v[4]“填充”v[3]而且记录v[4]现在是一个洞。
- 以此类推….
remove它返回一个指向最后一个的下一个“不删除的”元素的迭代器。返回值是区间的“新逻辑终点”。所以最后2个元素的由来也是这样。
所以我们一般使用erase配合remove来使用。如下:
vector<int> vec = { 1,1,2,2,3,3,4,4,5,6 };
cout << "Size:" << vec.size() << endl; //print
auto iter = std::remove(vec.begin(), vec.end(), 3);
vec.erase(iter, vec.end());
for (auto item : vec)
{
cout << " item:" << item << endl;
}
cout << "Size:" << vec.size() << endl; //print
可以得到如下的打印:
注意
要搞清这个例子的意思,记住下面这句话:
remove并不“真的”删除东西,因为它做不到
重复对你有好处:
remove并不“真的”删除东西, 因为它做不到
但是list容器自带一些成员函数比如:remove、erase、unique(删除邻近的重复值),也可以很方便的真的删除元素。
本文详细解析了C++标准库中的remove算法的工作原理及其局限性,指出remove实际上并不删除元素,而是将待删元素移至容器尾部,并通过示例展示了如何结合erase函数实现真正的元素删除。

1103

被折叠的 条评论
为什么被折叠?



