C++ STL 遍历 map 的时候如何删除其中的 element

来源:互联网 发布:淘宝假冒品牌仅退款 编辑:程序博客网 时间:2024/05/29 15:29

首先看一段他人的一段文章: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: 4Element key: 1, value: 2Element key: 2, value: 3Press any key to continue


在linux中运行结果为:

[zcm@t #19]$./tMap size1: 4Element key: 1, value: 2Element key: 2, value: 3Element key: 1, value: 2Element key: 3, value: 4Element key: 4, value: 5Map 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++;#endifdelCnt++;}elseit++;}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 1int c = delValue(map1, "3");cout << "delCnt = " << c << endl;#elsemap<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++;}#endifcout << "After delete, Map size = " << map1.size() << endl;display(map1);return 0;}


原创粉丝点击