首先看一段他人的一段文章:from: http://www.cnblogs.com/super119/archive/2011/10/11/2207541.html
我们通过map的erase(iterator it)方法删除元素的时候,如果此时erase处于遍历map的代码中,那么调用erase就需要小心一些。因为erase会导致输入参数iterator变的无效,从而影响后续的it++遍历map的逻辑。
简单做法是,先将要删除的it保存下来,然后将用于遍历map的it指向下一个位置,然后删除掉保存下来的it。如下面代码所示:
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main()
{
map<string, string> map1;
map<string, string>::iterator mapit;
map<string, string>::iterator saveit;
map1["1"] = "2";
map1["2"] = "3";
map1["3"] = "4";
map1["4"] = "5";
cout << "Map size1: " << map1.size() << endl;
mapit = map1.begin();
while (mapit != map1.end())
{
cout << "Element key: " << mapit->first << ", value: " << mapit->second << endl;
if (mapit->first == "2")
{
saveit = mapit;
mapit++;
map1.erase(saveit);
continue;
}
mapit++;
}
cout << "Map size2: " << map1.size() << endl;
return 0;
}
需要注意的是,这里windows的STL(windows C++编译器带的STL)和linux上的STL(gcc的STL)实现不同。
windows的STL中,map的erase方法会返回一个iterator,这个iterator指向的是当前被删除的iterator后面的iterator,所以这样的话,只需要将用于循环的iterator赋成erase函数的返回值就可以了。参考上面代码,就是这样:
mapit = map1.erase(mapit);然后continue就可以。
但是Linux下这样写代码是无法通过编译的。
--------------------------------------------------------------------------------------------------------------------------------------
另外,我将上面代码中的while()改了下:
while (mapit != map1.end())
{
cout << "Element key: " << mapit->first << ", value: " << mapit->second << endl;
if (mapit->first == "2")
{
saveit = mapit;
//mapit++;
map1.erase(saveit);
//continue;
}
mapit++;
}
经过修改之后,在vc6中调试时发现程序运行到mapit++;时就遇到了异常,不调试程序是可以正常运行下去的,但结果却不正确,而且与linux下的运行结果也不同。
上述修改后的代码在vc6中运行结果为:
Map size1: 4
Element key: 1, value: 2
Element key: 2, value: 3
Press any key to continue
在linux中运行结果为:
[zcm@t #19]$./t
Map size1: 4
Element key: 1, value: 2
Element key: 2, value: 3
Element key: 1, value: 2
Element key: 3, value: 4
Element key: 4, value: 5
Map size2: 3
注意到区别了吗?再仔细看看!
===========================================================
下面是一个更简单(看delValue函数)的写法,完整程序如下:
/*
map遍历并删除符合条件的元素
*/
#ifndef WIN32
#include <string.h> // Linux下得用此文件(strcmp要用到)
#else
#include <string>
#endif
#include <iostream>
#include <map>
using namespace std;
void display(map<string, string>& m)
{
for(map<string, string>::iterator it = m.begin(); it != m.end(); it++)
{
cout << "(" << it->first << ", " << it->second << ")" << endl;
}
cout << endl;
}
// 删除m中值为value的元素, 返回被删除元素的个数
int delValue(map<string, string>& m, const char* value)
{
int delCnt = 0; // 统计被删除元素个数
map<string, string>::iterator it = m.begin();
while(it != m.end())
{
if(strcmp(it->second.c_str(), value) == 0)
{
#if 1 // 此写法在windows和Linux上都OK(运行结果也正确)
m.erase(it++);
#else // 此写法在windows上运行程序无法正常退出,应该是卡在当前while出不来了
m.erase(it);
it++;
#endif
delCnt++;
}
else
it++;
}
return delCnt;
}
int main()
{
map<string, string> map1;
map1["1"] = "3";
map1["2"] = "3";
map1["3"] = "4";
map1["4"] = "3";
cout << "Before delete, Map size = " << map1.size() << endl;
display(map1);
#if 1
int c = delValue(map1, "3");
cout << "delCnt = " << c << endl;
#else
map<string, string>::iterator mapit;
map<string, string>::iterator saveit;
mapit = map1.begin();
while (mapit != map1.end())
{
cout << "Element key: " << mapit->first << ", value: " << mapit->second << endl;
if (mapit->first == "2")
{
saveit = mapit;
mapit++;
map1.erase(saveit);
continue;
}
mapit++;
}
#endif
cout << "After delete, Map size = " << map1.size() << endl;
display(map1);
return 0;
}