2012-01-25 78 views
8
Driver::~Driver() 
{ 
    AutoCritSec acsDriverList(m_csDriverList,true); 
    DRIVERLIST::iterator it = m_DriverList.begin(); 
    for(;it!=m_DriverList.end();it++) 
    { 
     if (it->second == this) 
     { 
      m_DriverList.erase(it); 
      it = m_DriverList.begin(); 
     } 
    } 
} 

當我在visual studio 2003中編譯我的程序時,我的程序表現良好。但是當我在2010年做的一樣,然後同時關閉應用程序,我得到這樣map/set迭代器不可遞增map/set迭代器不可遞增

Expression:map/set iterator not incrementable 

一些錯誤,當我按下忽略這一點,我得到

Expression:"standard c++ library out of range" && 0 

是否有任何人有任何的想法是什麼在這裏:我會非常感激任何人的任何建議。噸的感謝和溫暖的祝福。

回答

12

如果this是列表中的唯一元素,則會超出列表的末尾。

從列表中刪除this後,您重置it = m_DriverList.begin();。這可以。然後評估循環表達式(i++ from for語句),這會導致it超出範圍的末尾。

推進迭代器超過容器的末端會導致程序顯示未定義的行爲。最近版本的Visual C++有助於檢測程序的調試版本中的許多常見迭代器錯誤,並提出斷言來幫助您解決它們。

您可以通過刪除循環表達式,並將其移入一個else陳述解決問題:

while (it != m_DriverList.end()) 
{ 
    if (it->second == this) 
    { 
     m_DriverList.erase(it); 
     it = m_DriverList.begin(); 
    } 
    else 
    { 
     ++it; 
    } 
} 

雖然,每次你刪除一個元素是相當浪費重啓迭代。考慮使用由調用返回的迭代器,而不是使用到erase

it = m_DriverList.erase(it); 
+0

擦的好推薦/刪除。在這種特殊情況下,m_DriverList顯然是成對的容器,或者是某種類型的映射,因爲測試就在它上面 - >秒。而不是std :: remove,它需要std :: remove_if與lambda函數或比較函數。 –

+0

如果容器是一個映射(問題標題,訪問成員'second'),那麼我不認爲可以應用* erase-remove *成語。慣用法與您所使用的while循環相似,但不是重新開始迭代,而是複製並推進迭代器,然後擦除當前位置。 –

+0

@DavidRodríguez-dribeas @MarkTaylor:好的;我被變量名稱中的「List」分心了。在C++ 11中,'erase'將迭代器返回到下一個元素(或者如果沒有下一個元素,則返回到一個尾部),並且Visual C++ 2010支持這一點。 –

6

正確擦除成語關聯容器如下:

for (auto it = container.begin(); it != container.end() /* not hoisted */; /* no inc. */) 
{ 
    if (delete_condition) 
    { 
     container.erase(it++); 
    } 
    else 
    { 
     ++it; 
    } 
}