欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

c++迭代器失效的情況匯總

 更新時(shí)間:2020年06月08日 09:29:10   作者:Boblim  
這篇文章主要介紹了C++迭代器失效的幾種情況總結(jié),文中代碼非常詳細(xì),幫助大家更好的了解學(xué)習(xí),感興趣的朋友可以參考下

一、序列式容器(數(shù)組式容器)

對(duì)于序列式容器(如vector,deque),序列式容器就是數(shù)組式容器,刪除當(dāng)前的iterator會(huì)使后面所有元素的iterator都失效。這是因?yàn)関etor,deque使用了連續(xù)分配的內(nèi)存,刪除一個(gè)元素導(dǎo)致后面所有的元素會(huì)向前移動(dòng)一個(gè)位置。所以不能使用erase(iter++)的方式,還好erase方法可以返回下一個(gè)有效的iterator。

for (iter = cont.begin(); iter != cont.end();)
{
  (*it)->doSomething();
  if (shouldDelete(*iter))
   iter = cont.erase(iter); //erase刪除元素,返回下一個(gè)迭代器
  else
   ++iter;
}

迭代器失效:

void vectorTest()
{
  vector<int> container;
  for (int i = 0; i < 10; i++)
  {
    container.push_back(i);
  }

  vector<int>::iterator iter;
   for (iter = container.begin(); iter != container.end(); iter++)
  {
      if (*iter > 3)
       container.erase(iter);
  }

   for (iter = container.begin(); iter != container.end(); iter++)
  {
      cout<<*iter<<endl;
  }
}

報(bào)錯(cuò)是:vectoriterator not incrementable.

 迭代器在執(zhí)行++操作時(shí)報(bào)錯(cuò)!已經(jīng)失效的迭代器不能再進(jìn)行自增運(yùn)算了。++代碼大致實(shí)現(xiàn)如下:

_Myiter operator++(int)
{
  _Myiter _Tmp=*this;
  ++*this;
  return (_Tmp);
}

對(duì)于序列式容器,比如vector,刪除當(dāng)前的iterator會(huì)使后面所有元素的iterator都失效。這是因?yàn)轫樞蛉萜鲀?nèi)存是連續(xù)分配(分配一個(gè)數(shù)組作為內(nèi)存),刪除一個(gè)元素導(dǎo)致后面所有的元素會(huì)向前移動(dòng)一個(gè)位置。(刪除了一個(gè)元素,該元素后面的所有元素都要挪位置,所以,iter++,已經(jīng)指向的是未知內(nèi)存)。

但是erase方法可以返回下一個(gè)有效的iterator。所以代碼做如下修改,就OK了。

void vectorTest()
{
  vector<int> container;
  for (int i = 0; i < 10; i++)
  {
    container.push_back(i);
  }

  vector<int>::iterator iter;
  for (iter = container.begin(); iter != container.end();)
  {
      if (*iter > 3) {
        iter = container.erase(iter);
      }
      else {
        iter ++;
      }

  }

  for (iter = container.begin(); iter != container.end(); iter++)
  {
      cout<<*iter<<endl;
  }
}

總結(jié):vector是一個(gè)順序容器,在內(nèi)存中是一塊連續(xù)的內(nèi)存,當(dāng)刪除一個(gè)元素后,內(nèi)存中的數(shù)據(jù)會(huì)發(fā)生移動(dòng),以保證數(shù)據(jù)的緊湊。所以刪除一個(gè)數(shù)據(jù)后,其他數(shù)據(jù)的地址發(fā)生了變化,之前獲取的迭代器根據(jù)原有的信息就訪問不到正確的數(shù)據(jù)。

所以為了防止vector迭代器失效,常用如下方法:

for (iter = container.begin(); iter != container.end(); )
{
      if (*iter > 3)
       iter = container.erase(iter);  //erase的返回值是刪除元素下一個(gè)元素的迭代器
      else{
        iter++;
      }
}

這樣刪除后iter指向的元素后,返回的是下一個(gè)元素的迭代器,這個(gè)迭代器是vector內(nèi)存調(diào)整過后新的有效的迭代器。

二、關(guān)聯(lián)式容器

對(duì)于關(guān)聯(lián)容器(如map, set,multimap,multiset),刪除當(dāng)前的iterator,僅僅會(huì)使當(dāng)前的iterator失效,只要在erase時(shí),遞增當(dāng)前iterator即可。這是因?yàn)閙ap之類的容器,使用了紅黑樹來實(shí)現(xiàn),插入、刪除一個(gè)結(jié)點(diǎn)不會(huì)對(duì)其他結(jié)點(diǎn)造成影響。erase迭代器只是被刪元素的迭代器失效,但是返回值為void,所以要采用erase(iter++)的方式刪除迭代器。

for (iter = cont.begin(); it != cont.end();)
{
  (*iter)->doSomething();
  if (shouldDelete(*iter))
   cont.erase(iter++);
  else
   ++iter;
}

//測試錯(cuò)誤的Map刪除元素
void mapTest()
{
  map<int, string> dataMap;


  for (int i = 0; i < 100; i++)
  {
      string strValue = "Hello, World";

      stringstream ss;
      ss<<i;
      string tmpStrCount;
      ss>>tmpStrCount;
      strValue += tmpStrCount;
      dataMap.insert(make_pair(i, strValue));
  }

  cout<<"MAP元素內(nèi)容為:"<<endl;
   map<int, string>::iterator iter;
  for (iter = dataMap.begin(); iter != dataMap.end(); iter++)
  {
      int nKey = iter->first;
      string strValue = iter->second;
      cout<<strValue<<endl;
  }

  cout<<"內(nèi)容開始刪除:"<<endl;
  //刪除操作引發(fā)迭代器失效
  for (iter = dataMap.begin(); iter != dataMap.end();iter++)
  {
      int nKey = iter->first;
      string strValue = iter->second;

      if (nKey % 2 == 0)
      {
        dataMap.erase(iter);  //錯(cuò)誤

      }
      /* cout<<iter->second<<endl;*/
  }
}

出錯(cuò):

解析:dataMap.erase(iter)之后,iter就已經(jīng)失效了,所以iter無法自增,即iter++就會(huì)出bug.解決方案,就是在iter失效之前,先自增。

void mapTest()
{
  map<int, string> dataMap;


  for (int i = 0; i < 100; i++)
  {
      string strValue = "Hello, World";

      stringstream ss;
      ss<<i;
      string tmpStrCount;
      ss>>tmpStrCount;
      strValue += tmpStrCount;
      dataMap.insert(make_pair(i, strValue));
  }

  cout<<"MAP元素內(nèi)容為:"<<endl;
  map<int, string>::iterator iter;
  for (iter = dataMap.begin(); iter != dataMap.end(); iter++)
  {
      int nKey = iter->first;
      string strValue = iter->second;
      cout<<strValue<<endl;
  }

  cout<<"內(nèi)容開始刪除:"<<endl;
  for (iter = dataMap.begin(); iter != dataMap.end();)
  {
      int nKey = iter->first;
      string strValue = iter->second;

      if (nKey % 2 == 0)
      {
        dataMap.erase(iter++);
        auto a = iter;

      }
      else {
        iter ++;
      }
  }
}

解析:dataMap.erase(iter++);這句話分三步走,先把iter傳值到erase里面,然后iter自增,然后執(zhí)行erase,所以iter在失效前已經(jīng)自增了。

map是關(guān)聯(lián)容器,以紅黑樹或者平衡二叉樹組織數(shù)據(jù),雖然刪除了一個(gè)元素,整棵樹也會(huì)調(diào)整,以符合紅黑樹或者二叉樹的規(guī)范,但是單個(gè)節(jié)點(diǎn)在內(nèi)存中的地址沒有變化,變化的是各節(jié)點(diǎn)之間的指向關(guān)系。

所以在map中為了防止迭代器失效,在有刪除操作時(shí),常用如下方法:

for (iter = dataMap.begin(); iter != dataMap.end(); )
{
     int nKey = iter->first;
     string strValue = iter->second;

     if (nKey % 2 == 0)
     {
        map<int, string>::iterator tmpIter = iter;
      iter++;
        dataMap.erase(tmpIter);
        //dataMap.erase(iter++) 這樣也行

     }else
   {
     iter++;
     }
}

三、鏈表式容器

對(duì)于鏈表式容器(如list),刪除當(dāng)前的iterator,僅僅會(huì)使當(dāng)前的iterator失效,這是因?yàn)閘ist之類的容器,使用了鏈表來實(shí)現(xiàn),插入、刪除一個(gè)結(jié)點(diǎn)不會(huì)對(duì)其他結(jié)點(diǎn)造成影響。只要在erase時(shí),遞增當(dāng)前iterator即可,并且erase方法可以返回下一個(gè)有效的iterator。

方式一:遞增當(dāng)前iterator

for (iter = cont.begin(); it != cont.end();)
{
  (*iter)->doSomething();
  if (shouldDelete(*iter))
   cont.erase(iter++);
  else
   ++iter;
}

方式二:通過erase獲得下一個(gè)有效的iterator

for (iter = cont.begin(); iter != cont.end();)
{
  (*it)->doSomething();
  if (shouldDelete(*iter))
   iter = cont.erase(iter); //erase刪除元素,返回下一個(gè)迭代器
  else
   ++iter;
}

四、總結(jié)

迭代器失效分三種情況考慮,也是分三種數(shù)據(jù)結(jié)構(gòu)考慮,分別為數(shù)組型,鏈表型,樹型數(shù)據(jù)結(jié)構(gòu)。

數(shù)組型數(shù)據(jù)結(jié)構(gòu):該數(shù)據(jù)結(jié)構(gòu)的元素是分配在連續(xù)的內(nèi)存中,insert和erase操作,都會(huì)使得刪除點(diǎn)和插入點(diǎn)之后的元素挪位置,所以,插入點(diǎn)和刪除掉之后的迭代器全部失效,也就是說insert(*iter)(或erase(*iter)),然后在iter++,是沒有意義的。解決方法:erase(*iter)的返回值是下一個(gè)有效迭代器的值。 iter =cont.erase(iter);

鏈表型數(shù)據(jù)結(jié)構(gòu):對(duì)于list型的數(shù)據(jù)結(jié)構(gòu),使用了不連續(xù)分配的內(nèi)存,刪除運(yùn)算使指向刪除位置的迭代器失效,但是不會(huì)失效其他迭代器.解決辦法兩種,erase(*iter)會(huì)返回下一個(gè)有效迭代器的值,或者erase(iter++).

樹形數(shù)據(jù)結(jié)構(gòu): 使用紅黑樹來存儲(chǔ)數(shù)據(jù),插入不會(huì)使得任何迭代器失效;刪除運(yùn)算使指向刪除位置的迭代器失效,但是不會(huì)失效其他迭代器.erase迭代器只是被刪元素的迭代器失效,但是返回值為void,所以要采用erase(iter++)的方式刪除迭代器。

注意:經(jīng)過erase(iter)之后的迭代器完全失效,該迭代器iter不能參與任何運(yùn)算,包括iter++,*ite

以上就是c++迭代器失效的情況匯總的詳細(xì)內(nèi)容,更多關(guān)于c++迭代器失效的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C++棧的數(shù)組實(shí)現(xiàn)代碼

    C++棧的數(shù)組實(shí)現(xiàn)代碼

    這篇文章主要介紹了C++棧的數(shù)組實(shí)現(xiàn)方式,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-05-05
  • 函數(shù)外初始化與函數(shù)內(nèi)初始化詳細(xì)解析

    函數(shù)外初始化與函數(shù)內(nèi)初始化詳細(xì)解析

    函數(shù)內(nèi)初始化:bool FillStr(char *&szDst, int nSize);第一個(gè)參數(shù)中的&一定不能少,這是因?yàn)樵诤瘮?shù)外部我們只聲明了這個(gè)指針,具體這個(gè)指針指向內(nèi)存中的哪個(gè)地址我們并不知道,所以&是為了說明傳遞的是這個(gè)指針的引用,那么在函數(shù)內(nèi)初始化后這個(gè)指針的地址也就是外面指針的地址了
    2013-09-09
  • OpenCV中C++函數(shù)imread讀取圖片的問題及解決方法

    OpenCV中C++函數(shù)imread讀取圖片的問題及解決方法

    利用C++函數(shù)imread讀取圖片的時(shí)候返回的結(jié)果總是空,而利用C函數(shù)cvLoadImage時(shí)卻能讀取到圖像。怎么回事?今天小編通過本教程給大家簡單說明原因
    2017-03-03
  • C++編程之CString、string與、char數(shù)組的轉(zhuǎn)換

    C++編程之CString、string與、char數(shù)組的轉(zhuǎn)換

    這篇文章主要介紹了C++編程之CString、string與、char數(shù)組的轉(zhuǎn)換的相關(guān)資料,希望通過本文能幫助到大家,讓大家學(xué)習(xí)理解這部分內(nèi)容,需要的朋友可以參考下
    2017-10-10
  • VC創(chuàng)建DLL動(dòng)態(tài)鏈接庫的方法

    VC創(chuàng)建DLL動(dòng)態(tài)鏈接庫的方法

    這篇文章主要介紹了VC創(chuàng)建DLL動(dòng)態(tài)鏈接庫的方法,實(shí)例分析VC創(chuàng)建動(dòng)態(tài)鏈接庫的完整步驟,需要的朋友可以參考下
    2015-05-05
  • C語言數(shù)據(jù)結(jié)構(gòu)之二叉樹詳解

    C語言數(shù)據(jù)結(jié)構(gòu)之二叉樹詳解

    二叉樹(Binary tree)是樹形結(jié)構(gòu)的一個(gè)重要類型。許多實(shí)際問題抽象出來的數(shù)據(jù)結(jié)構(gòu)往往是二叉樹形式。本文將通過示例詳細(xì)講解一下二叉樹,需要的可以參考一下
    2022-03-03
  • QT中QByteArray與char、int、float之間的互相轉(zhuǎn)化

    QT中QByteArray與char、int、float之間的互相轉(zhuǎn)化

    本文主要介紹了QT中QByteArray與char、int、float之間的互相轉(zhuǎn)化,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • C++實(shí)現(xiàn)LeetCode(187.求重復(fù)的DNA序列)

    C++實(shí)現(xiàn)LeetCode(187.求重復(fù)的DNA序列)

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(187.求重復(fù)的DNA序列),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C語言實(shí)現(xiàn)火車訂票系統(tǒng)

    C語言實(shí)現(xiàn)火車訂票系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)火車訂票系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • c++11 atomic的使用詳解

    c++11 atomic的使用詳解

    這篇文章主要介紹了c++11 atomic的使用詳解,幫助大家更好的理解和學(xué)習(xí)使用c++,感興趣的朋友可以了解下
    2021-02-02

最新評(píng)論