2016-04-22 13 views
3

マップ(std :: map)をループしているときに問題が発生しています。私のループ内マップ上のC++ループがマップの終わりの変化を検出しない

、この同じマップの要素を消去し、時には(常にではない)関数の呼び出しがあります。この関数を使用した後、このマップ情報のいくつかを入力として使用しているコードがあります。この機能は、マップの最後要素が消去されユニーク場合を除いて、すべての要素を消去した後

私は問題のないています。

マイループSEMMSはマップの最後の要素は、それが動作し始めたときと同じではないことを理解すると、クラッシュを作成し、存在doesntの要素を操作しようとしません。

ループの説明にmyMap.end()の呼び出しは、マップの新しいエンド()を使用して自身を更新することができないように私には思えます。

コードの関連部分を以下にリストされている:

for(std::map<int, ConnectionInfo>::iterator kv = myMap.begin(); kv != myMap.end(); ++kv) { 
     int thisConnectionID=kv->first; //This is where I get garbage when the loop enters when it shouldnt; 
     ConnectionInfo currentConnectionInfo=kv->second; //This is where I get garbage when the loop enters when it shouldnt; 
     status=eraseSomeMapElementsIfNecessary(thisConnectionID,currentConnectionInfo.DownPacket); //this function might erase elements on myMap. This generates no problems afterwards, except when the end element of myMap is erased 
     ... //Next parts of the code make no further usage of myMaps, so I just hid it not to pollute the code 
} 

kv != myMap.end()は、内側のループは(消去)MYMAPの最後の要素(最後に)変化していることを理解できていないことを私の解釈です?

この場合、この問題を解決するにはどうすればよいですか?

私の解釈は間違っていますが、ソリューションは以前に述べたこととは何の関係もありません。

ありがとうございました!

+0

必須であるため、コードの '... '部分を表示します。ほとんどの場合、ある時点で無効なイテレータを取得している可能性があります。 –

+3

マップから要素を消去すると、イテレータが無効になる –

+0

erase_ifを使用する方がよい場合があります(実装で提供されている場合)http://en.cppreference.com/w/cpp/experimental/map/erase_if – porges

答えて

5

通常のイディオム可能性の要素を削除してマップを反復です:

for(auto it = map.begin(); it != map.end();) { 
    if (*it == /*is to delete*/) { 
    it = map.erase(it); 
    } 
    else 
    ++it; 
} 

あなたeraseSomeMapElementsIfNecessaryは必ず問題を引き起こすため、この意志を反復されているマップ内のいくつかのランダムな値を消去する可能性がある場合。 itが参照している要素が消去されると無効になり、++ititをインクリメントすることも無効になります。

問題は実際にはitイテレータでのみ発生し、eraseSomeMapElementsIfNecessaryがそれを消去して使用すると、未定義ビヘイビア(UB)が発生します。だから、解決策は、反復するために、次のいずれかをeraseSomeMapElementsIfNecessaryに現在のイテレータを渡し、そこから返すことです:

it = eraseSomeMapElementsIfNecessary(it); 

私の例から、forループのボディはあなたのeraseSomeMapElementsIfNecessary関数内でなければなりません。少なくともこれは1つの解決策です。

+0

1)eraseSomeMapElementsIfNecessary関数をループで調整して、この問題を解決するにはどうすればよいですか? 2)「UB」とはどういう意味ですか? – user9589

+0

@ user9589未定義の動作 - アプリケーションがクラッシュするか、または期待どおりに動作する可能性があることを意味します。何か – marcinj

+2

ad1)eraseSomeMapElementsIfNecessary関数にイレーズイディオムを消去した上のマップを置く必要があります。私は上にそれを行う方法のヒントを与えました。 – marcinj

4

マップの最後の要素が消去されているというユニークなケースを除いて、この機能がすべての要素を消去しても問題はありません。

任意のコンテナの要素を消去すると、反復子が無効になります。その後、無効化されたイテレータをインクリメントします。

イテレータをポイントする要素を削除する前に、イテレータをインクリメントする必要があります。

ループ内でどのような要素が機能しているのかわからない場合は、すべてのイテレータが無効になっていると仮定します。

+0

OP-s関数はこれを行います: '//この関数はmyMapの要素を消去するかもしれないので、マップ内の要素を消去する可能性があるので、消去の前にイテレータをインクリメントすることは役に立ちません。 – marcinj

+0

@MarcinJędrzejewski真実、私は根本的な原因を文書化しました。 –

0

現在のイテレータを消去する前に、次のイテレータを保持する必要があります。現在の要素は要素を削除した後に無効になるからです。

auto nextit = it+1; 
map.erase(it); 
it = nextit; 
関連する問題