std::map的安全遍歷並刪除元素的方法

首先咱們講遍歷std::map, 大部分人都能寫出第一種遍歷的方法,但這種遍歷刪除的方式並不太安全。ios

第一種 for循環變量:緩存

#include<map>
#include<string>
#include<iostream>
using namespace std;

int main()
{
    map<int,string*> m;
    m[1]= new string("1111111111111111");
    m[2]= new string("2222222222222222");
    m[3]= new string("3333333333333333");
    m[4]= new string("4444444444444444");
    m[0]= new string("5555555555555555");
    map<int,string*>::iterator it;
    for(it=m.begin();it!=m.end();++it)
    {
        cout<<"key: "<<it->first <<" value: "<<*it->second<<endl;
        delete it->second;
        m.erase(it);
    }
return   0;
}

結果以下:安全

key: 0 value: 5555555555555555
key: 1 value: 1111111111111111
key: 2 value: 2222222222222222
key: 3 value: 3333333333333333
key: 4 value: 4444444444444444函數

第二種while循環的遍歷:spa

#include <map>
#include <string>
#include <iostream>
#include <cstring>
using namespace std;

struct ltstr
{
  bool operator()(const char* s1, const char* s2) const
  {
    return strcmp(s1, s2) < 0;
  }
};

int main()
{
  map<const char*, int, ltstr> ages;
  ages["Homer"] = 38;
  ages["Marge"] = 37;
  ages["Lisa"] = 8;
  ages["Maggie"] = 1;
  ages["Bart"] = 11;

  while( !ages.empty() ) {
    cout << "Erasing: " << (*ages.begin()).first << ", " << (*ages.begin()).second << endl;
    ages.erase( ages.begin() );
  }

}

運行結果:code

Erasing: Bart, 11
Erasing: Homer, 38
Erasing: Lisa, 8
Erasing: Maggie, 1
Erasing: Marge, 37blog

第三種更安全的for 循環遍歷:進程

#include<map>
#include<string>
#include<iostream>
using namespace std;

int main()
{
    map<int,string*> m;
    m[1]= new string("1111111111111111");
    m[2]= new string("2222222222222222");
    m[3]= new string("3333333333333333");
    m[4]= new string("4444444444444444");
    m[0]= new string("5555555555555555");
    map<int,string*>::iterator it;
    for(it=m.begin();it!=m.end();)
    {
        cout<<"key: "<<it->first <<" value: "<<*it->second<<endl;
        delete it->second;
        m.erase(it++);
    }
    return   0;
}

運行結果與第一種方式相同,不過這種刪除方式也是STL源碼一書中推薦的方式,分析 m.erase(it++)語句,map中在刪除iter的時候,先將iter作緩存,而後執行iter++使之指向下一個結點,再進入erase函數體中執行刪除操做,刪除時使用的iter就是緩存下來的iter(也就是當前iter(作了加操做以後的iter)所指向結點的上一個結點)。源碼

    根據以上分析,能夠看出(m.erase(it++) )和(m.erase(it); iter++; )這個執行序列是不相同的。前者在erase執行前進行了加操做,在it被刪除(失效)前進行了加操做,是安全的;後者是在erase執行後才進行加操做,而此時iter已經被刪除(當前的迭代器已經失效了),對一個已經失效的迭代器進行加操做,行爲是不可預期的,這種寫法勢必會致使 map操做的失敗並引發進程的異常。string

相關文章
相關標籤/搜索