从容器中删除元素,唯一的办法是调用容器的成员函数,几乎总是erase的某种形式。因为从容器中删除元素的唯一方法是调用容器的成员函数,而remove算法并不知道它操作的元素所在的容器,所以remove不可能从容器中删除元素。使用remove算法从容器中删除元素,容器中的元素不会因此而减少。
remove算法不是真正意义上的删除,因为它做不到。
remove算法移动了区间中的元素,“不用被删除”的元素已到了区间的前部(保存原来的相对顺序)。它返回一个迭代器指向最后一个"不用被删除"的元素之后的元素。这个返回值相当于该区间的"新的逻辑结尾"。
从容器中删除元素的正确方法:
序列容器(以vector为例):
std::vector<int> datas;
...初始化datas
int destData = 10;
...
datas.erase(std::remove(datas.begin(), datas.end(), destData), datas.end());
list:
std::list<int> datas;
...初始化datas
int destData = 10;
...
datas.remove(10);
关联容器(以map为例):
std::map<int, int> datas;
...初始化datas
datas.erase(10);
需要注意的是:
list中的remove是真正可以将被删除元素从容器中删除的,等同于调用了erase-remove方法。
和remove算法类似的算法还有remove_if和unique,它们都是将不需要的元素放入容器的后面,然后返回一个迭代器。
同时针对它们,list中也有相应的成员函数remove_if和unique。它们都会将不需要的元素删除掉。
下面是SGL STL中remove算法的源码:
// 将不等于目标值的元素依次赋值给_result
template <class _InputIter, class _OutputIter, class _Tp>
_OutputIter remove_copy(_InputIter __first, _InputIter __last, _OutputIter __result, const _Tp& __value)
{
__STL_REQUIRES(_InputIter, _InputIterator);
__STL_REQUIRES(_OutputIter, _OutputIterator);
__STL_REQUIRES_BINARY_OP(_OP_EQUAL, bool, typename iterator_traits<_InputIter>::value_type, _Tp);
for (; __first != __last; ++__first)
if (!(*__first == __value))
{
*__result = *__first;
++__result;
}
return __result;
}
template <class _ForwardIter, class _Tp>
_ForwardIter remove(_ForwardIter __first, _ForwardIter __last, const _Tp& __value) {
__STL_REQUIRES(_ForwardIter, _Mutable_ForwardIterator);
__STL_REQUIRES_BINARY_OP(_OP_EQUAL, bool, typename iterator_traits<_ForwardIter>::value_type, _Tp);
__STL_CONVERTIBLE(_Tp, typename iterator_traits<_ForwardIter>::value_type);
__first = find(__first, __last, __value); // 找到第一个等于目标值的位置
_ForwardIter __i = __first;
// 如果容器中没有目标值,直接返回容器的起始地址;否则从第一个目标值位置的下一个元素开始执行remove_copy
return __first == __last ? __first : remove_copy(++__i, __last, __first, __value);
}
算法示例:
使用一个实际例子来分解remove算法,容器中的元素为 1 2 3 4 3 5,删除的元素为3,下面是每一步的分解:
1 2 3® 4(f) 3 5:__result指向3,__first指向4,将4赋值给3,序列变为:1 2 4 4 3 5
1 2 4 4® 3 5(f):__result指向第二个4, __first指向5, 将5赋值4,序列变为 :1 2 4 5 3 5
1 2 4 5 3® 5:__result指向3,__first指向容器end(),算法结束,返回__result指向3