2016-11-17 5 views
0

なぜValgrindは次の行にInvalid read of size 4と表示されますか?サイズ4のイテレーターが無効です。

for (map<uint16_t, SPacket *>::iterator it = m_PacketMap.begin() ; it != m_PacketMap.end(); ++it) 
{ 
    if (it->first < ackNumber) 
    { 
     if (it->second->data) delete [] it->second->data; 
     if (it->second) delete it->second; 
     m_PacketMap.erase(it); 
    } 
} 

私はループの前にそのm_PacketMap.size() > 0を確認し、一時的にm_PacketMapの内容を確認するために、ループの前にデバッグを追加しましたが、期待どおりにすべてが見えてきました。これは、ValgrindのエラーメッセージとRadioManager.cppさ:

==5535== Invalid read of size 4 
==5535== at 0x421EBE5: std::_Rb_tree_increment(std::_Rb_tree_node_base*) (in /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16) 
==5535== by 0x80AD20D: RadioManager::DecodeAcknowledgementNumber(unsigned char*, unsigned int) (RadioManager.cpp:1042) 

これはSPacketとm_PacketMapは問題が私のイテレータ、可能な問題であり

typedef struct SPacket 
{ 
    uint8_t * data; 
    size_t size; 
    timeval tval; 
} SPacket; 
map<uint16_t, SPacket *> m_PacketMap; 

を定義する方法である:1042は、ライン上にあります_Rb_tree_increment、または完全に他の何かで?あなたがしなければならない

+0

はい。それらがキーと一致する場合、私はマップエントリを消去しています。私は元の質問に本文を追加します。ああ私はあなたが何を得ているかを見ていると思う。コンテナが縮小しているときのイテレータの動作 – jacknad

答えて

3

forループからのコンテナ要素を消去することは注意して行う必要があります...

map<uint16_t, SPacket *>::iterator it = m_PacketMap.begin() 
while (it != m_PacketMap.end()) 
{ 
    if (it->first < ackNumber) 
    { 
     if (it->second->data) delete [] it->second->data; 
     if (it->second) delete it->second; 
     // it updated by erase, no need to increment 
     it = m_PacketMap.erase(it); 
    } 
    else 
    { 
     // move to next item 
     ++it; 
    } 
} 

コンテナのいくつかの要素を取り除くループが書かれなければならない方法です(セット、ベクトル...のために同じように動作します)。

マップの場合、上記のコードはC++ 11でのみ動作します。以前のバージョンを使用している場合は、this post(テストしていない)によると、あなたが実行する必要があります。

for (map<uint16_t, SPacket *>::iterator it = m_PacketMap.begin(); it != m_PacketMap.end(); ) 
{ 
    if (it->first < ackNumber) 
    { 
     if (it->second->data) delete [] it->second->data; 
     if (it->second) delete it->second; 
     // it updated by erase, no need to increment 
     m_PacketMap.erase(it++); 
    } 
    else 
    { 
     // move to next item 
     ++it; 
    } 
} 

ので、(あなたがforループでやって終わる何を)あなた緩い要素を行います、それを増分その項目を消去し、 m_PacketMap.end()を通過する可能性があります(そして、コンテナの最後の要素を消去すると、ループの項目がコンテナの範囲外になります)。

+0

m_SentPacketMapはtypoです – jacknad

+0

'm_PacketMap.erase(it ++)'は 'm_PacketMap.erase(it)'にする必要がありますか? – jacknad

+0

以前のバージョン( 'it = m_PacketMap.erase(it);'はコンパイルしないでください)では、 'it = m_PacketMap.erase(it);' for C++ 11、 'm_PacketMap.erase(it ++);' – jpo38

1

要素を削除すると、itが無効になり、次にitが増えます。無効なイテレータをインクリメントすることはできません。

コードを-D_GLIBCXX_DEBUGで再構築すると、無効なイテレータ操作で中止するlibstdC++デバッグモードが有効になります。

deleteを使用する前に、nullポインタでないポインタをテストする必要はありません。ヌルポインタにdeleteを使用すると安全です(nullをチェックするので、不要な値を追加するだけです)。重複チェック)。

関連する問題