2016-11-17 54 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:1042線以上:

==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; 

是否有一個問題,我的迭代器,一個可能的問題在_Rb_tree_increment中,還是其他的東西?從for循環

+0

是的。如果他們匹配密鑰,我正在清除地圖條目。我將添加正文到原始問題。啊。我想我明白你在做什麼。當容器縮小時,迭代器如何工作? – jacknad

回答

3

刪除容器元素,必須小心做...

你必須做到:

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; 
    } 
} 

這是一個循環取出容器的一些要素必須被寫入的方式(對於set,vector ...來說工作是一樣的)。

對於地圖,上述代碼僅適用於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是一個輸入錯誤 – jacknad

+0

m_PacketMap.erase(it ++)是否應該是m_PacketMap.erase(it)? – jacknad

+0

'it = m_PacketMap.erase(it);'對於C++ 11,'m_PacketMap.erase(it ++);'對於早期版本('it = m_PacketMap.erase(it);'不應該編譯) – jpo38

1

您刪除的元素,這使得it無效的,那麼你就增加it。你不能增加一個無效的迭代器。

-D_GLIBCXX_DEBUG重建你的代碼將使++的libstdc調試模式,這將中止對無效迭代器操作。

無關Valgrind的錯誤,你並不需要測試的指針不是null進行delete之前,因爲它是安全的,對空指針使用delete(它會檢查空,無論如何,所以你只是增加不必要的重複檢查)。

相關問題