目录
更多STL面试题参见:C++面试题系列:STL
1.引例
题目: 删除map<int, int>中value为5的倍数的元素
删除STL容器vector、map中的元素,容易引起迭代器失效问题。
map的erase()方法处理方式,代码1-1:
// VectorMapIterator.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <map>
using namespace std;
typedef map<int, int> Map;
typedef map<int, int>::iterator MapIt;
void print(Map &m)
{
MapIt it;
for(it = m.begin(); it != m.end(); it++)
{
cout << it->second << " ";
}
cout << endl;
}
void deleteValueFromMap(Map &m, int n = 5)
{
MapIt it,mit;
MapIt tmp;
for(it = m.begin(); it != m.end();)
{
if(0 == it->second % n)
{
tmp=it++;
if (it !=m.end())
{
cout<<"tmp:"<<tmp->second<<";it:"<<it->second<<endl;
}
m.erase(tmp);
}else{
it++;
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
Map m;
int i = 0;
for(i = 0; i < 21; i++)
{
m[i] = i;
}
print(m);
deleteValueFromMap(m); // 程序崩溃
print(m);
return 0;
}
vector的erase()方法处理方式,代码1-2:
// VectorIterator.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <vector>
using namespace std;
typedef vector<int> Vec;
typedef vector<int>::iterator VecIt;
void print(Vec &v)
{
VecIt it;
for(it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void deleteValueFromVector(Vec &v, int n = 5)
{
VecIt it;
for(it = v.begin(); it != v.end(); /*不能再自增了*/)
{
if(0 == *it % n)
{
//vector的erase实现都会返回一个迭代器,这个迭代器指向了“当前删除元素的后继元素,或是end()”
it=v.erase(it);
}
else
{
it++;
}
}
}
int main()
{
Vec v;
int i = 0;
for(i = 0; i < 21; i++)
{
v.push_back(i); // 不能再傻傻地用下标了
}
print(v);
deleteValueFromVector(v); // 程序ok
print(v);
return 0;
}
2.迭代器失效
对于vector、deque,他们是序列式容器;序列式容器是组合式容器,当当前元素的iterator被删除后,其后的所有元素的迭代器都会失效,这是因为vector,deque都是连续存储的一段空间,当对其进行erase操作时,其后的每一个元素都会向前移一个位置。
迭代器失效时会返回下一个有效的迭代器,it=erase(it)。处理方式见,代码1-2。
对于list,set,map,删除时只有被删除节点迭代器失效,处理方式在当前迭代器失效前指向下一个迭代器,即erase(it++)。
这里主要解释一下erase(it++)的执行过程:这句话分三步走,先把iter传值到erase里面,然后iter自增,然后执行erase,所以iter在失效前已经自增了。
参考文献: