Erase-Remove 惯用法
看到《Effective STL》条款 9 的时候想到了我以前复习的“如何正确使用迭代器删除元素”,我面试时使用的也是里面的方法,看面试官的反应好像也没有什么问题,还问了我一些我早已整理过的考点。但看到条款 9 之后,我就觉得自己以前回答得没什么水平了。
文本参考了条款 9 和条款 32。
remove()
<algorithm>
中的 remove()
的声明为:
template<class ForwardIt, class T>
ForwardIt remove(ForwardIt first, ForwardIt last, const T& value);
也就是从范围 [first, last) 内移除所有满足特定判别标准的元素,并返回新结尾的尾后迭代器。需要注意的是,remove()
并不真正删除东西,因为它做不到。remove()
移动指定区间中的所有元素直到所有“不删除的”元素在区间的开头(相对位置和原来的一样)。它返回一个指向最后一个“不删除的”元素的下一个元素的迭代器。返回值是区间的“新逻辑终点”。
vector<int> v;
v.reserver(10);
for(int i = 1; i <= 10; ++i)
{
v.push_back(i);
}
v[3] = v[5] = v[9] = 99;
vecitor<int>::iterator newEnd(remove(v.begin(), v.end(), 99));
调用 remove()
之前:
调用 remove()
之后:
erase-remove 惯用法
如果要真正删除东西的话,应该在 remove()
后面接上 erase()
。要 erase()
的元素很容易识别:它们是从区间的“新逻辑终点”开始持续到区间真正重点的原来区间的元素。要除去那些元素,要做的事情就是用两个迭代器调用 erase()
的区间形式。
vector<int> v;
v.erase(remove(v.begin(), v.end(), 99), v.end());
把 remove
的返回值作为 erase()
区间形式第一个实参传递很常见,这是个惯用法。
remove_if() 和 remove_copy_if()
序列容器
如果要删除的不是每个有特定值的物体,而是消除下面的判断式
bool badValue(int x); // 返回 x 是否是 "bad".
对于序列容器,要做的只是把每个 remove()
替换成 remove_if()
,然后就完成了:
c.erase(remove_if(c.begin(), c.end(), badValue), c.end());
这样面试题“从 vector
中删除 3 的倍数”就变得更简单了:
bool ThreeTimes(int num)
{
return num % 3 == 0 ? true : false;
}
int main()
{
// ...
// 一行代码, 没有循环.
vec.erase(std::remove_if(vec.begin(), vec.end(), ThreeTimes), vec.end());
// ...
}
真是好笑,听到面试官问我这道题,我心中窃喜,还想着秀一秀我关于“如何正确使用迭代器删除元素”的清晰思路,哈哈,真是贻笑大方