2012-01-25 41 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/iteratorはインクリメンタルマップではありません。インクリメンタルではありません。

Expression:map/set iterator not incrementable 

のようないくつかのエラーを取得し、私はこれを無視して押したとき、私は

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

は、いずれかが何であるか任意のアイデアを持ってい取得しますここに行く:私は誰にでも何か提案があれば、非常に恩恵を受けるだろう。感謝の気持ちと暖かい願い。

答えて

12

thisがリスト内の唯一の要素である場合は、リストの末尾がオーバーランします。

thisをリストから削除すると、it = m_DriverList.begin();がリセットされます。これは問題ありません。ループの式が評価され(forステートメントのi++)、itが範囲の最後を過ぎて進んでいます。

反復子をコンテナの最後まで進めると、プログラムは未定義の動作を示します。最近のバージョンのVisual C++では、プログラムのデバッグビルドで多くの一般的なイテレータエラーが検出され、アサーションを作成して解決するのに役立ちます。

あなたは、ループ式を削除し、else声明にそれを移動することで問題を解決できます。

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

けれども、あなたが要素かなり無駄であるを削除するたびに反復再起動します。

it = m_DriverList.erase(it); 
+0

グッド勧告eraseへの呼び出しによって返されたイテレータを使用して使用する代わりに考えてみましょう。この特定のケースでは、明らかにm_DriverListはペアのコンテナであるか、またはテストがそれ以上であるため何らかの種類のマップです。 std :: removeの代わりに、ラムダ関数または比較関数を使ってstd :: remove_ifが必要になります。 –

+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; 
    } 
} 
関連する問題