为什么Valgrind会在以下行中显示Invalid read of size 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中可能存在问题,还是其他问题?
答案 0 :(得分:3)
从False
循环中删除容器元素必须小心......
你必须这样做:
for
这就是必须编写一个删除容器的某些元素的循环的方式(对于set,vector也是一样的。)。
对于地图,上面的代码仅适用于C ++ 11。如果你使用的是早期版本,根据this post(未经测试),你应该这样做:
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;
}
}
因为删除项目然后递增它(你最后用你的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
(然后让你的循环覆盖项目如果从容器中删除最后一个元素,则为容器的限制。
答案 1 :(得分:1)
删除一个元素,使it
无效,然后递增it
。你不能增加无效的迭代器。
使用-D_GLIBCXX_DEBUG
重建代码将启用libstdc ++调试模式,该模式将在无效的迭代器操作上中止。
与valgrind错误无关,在使用delete
之前,您不需要测试指针是否为空,因为在空指针上使用delete
是安全的(无论如何它都会检查null)所以你只是添加了不必要的重复检查。)