C++ STL容器遍历删除元素的方法
上周在做内存池回收的时候,遍历deque(使用了双端队列来管理内存块)的每一个元素,查找满足条件的内存块并进行回收,结果竟然coredump了。
写了个简单的测试代码:
#include <deque>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
deque<int> deque_int;
deque_int.push_back(1);
deque_int.push_back(2);
deque_int.push_back(3);
deque_int.push_back(4);
deque_int.push_back(5);
for_each(deque_int.begin(), deque_int.end(), [&](int n){ cout << n << " ";});
cout << endl;
deque<int>::iterator it;
for (it = deque_int.begin(); it != deque_int.end(); it++) {
if ((*it) == 2 || (*it) == 4) {
deque_int.erase(it);
}
}
cout << "after erase." << endl;
for_each(deque_int.begin(), deque_int.end(), [&](int n){ cout << n << " ";});
cout << endl;
return 0;
}
上面的程序运行起来起来很OK,嗯,至少从运行结果来看是符合预期的:
再去看自己内存池部分代码,分析删除的元素是deque的最后一个元素,好吧,把这里也改为删除最后一个元素:
for (it = deque_int.begin(); it != deque_int.end(); it++) {
if ((*it) == 5) {
deque_int.erase(it);
}
}
编译,运行:
真的core了!!!
问题找到了,但是逻辑没问题的呀(嗯,表面上看确实如此)。
分析,在erase最后一个元素之后,在进入下一次循环之前,it++后it指向的是删除操作之前的deque的end,这样在比较it != deque_int.end()时,你以为应该是false了,实际它还是true。(有一句话这么说,“人不能两次踏进同一条河流”,现在的end,已经不是之前的那个end了)本该结束循环的,结果再次进入了循环,访问了一个非法地址,导致了core. 验证也确实如此。
好,原来竟是这样,那就该找解决办法了。
在C++ reference里边,deque的erase方法有这样一段:
Return value
An iterator pointing to the new location of the element that followed the last element erased by the function call. This is the container end if the operation erased the last element in the sequence.
那么就可以用这个返回值来做点文章:
for (it = deque_int.begin(); it != deque_int.end(); ) {
if ((*it) == 2 || (*it) == 3 || (*it) == 5) {
it = deque_int.erase(it);
continue;
}
it++;
}
这回挺和谐了:
本文通过一个实例探讨了C++ STL中deque容器遍历删除元素时出现的问题及解决方案。详细分析了当删除deque最后一个元素时导致core dump的原因,并给出了正确的遍历删除方法。
8776

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



