迭代器无效读取大小4

时间:2016-11-17 18:58:49

标签: c++ dictionary iterator valgrind

为什么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中可能存在问题,还是其他问题?

2 个答案:

答案 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)所以你只是添加了不必要的重复检查。)