擦除后c ++ boost map程序崩溃

时间:2014-11-06 00:41:00

标签: c++ boost

我有一个问题,不知道如何正确解决它或为什么出现错误。

对我的问题: 我有1个循环,每2秒执行一次函数。该函数执行for()函数并擦除剩余时间为0的所有寄存。如果剩余时间不为0则将其减少2000(2秒)。

但在删除一个条目后程序崩溃了......

提升地图:

boost::unordered_map<unsigned int, sBUFF_INFO*> p_BuffInfo;

从2秒循环执行的函数

void CSkill::DecreaseAllBuffRemTime()
{
    for( itertype(p_BuffInfo) it = p_BuffInfo.begin(); it != p_BuffInfo.end(); it++ )
    {
        sBUFF_INFO* buff = it->second;
        if(buff != NULL)
        {
            if(buff->dwTimeRemaining <= 0)
            {
                this->DelPcBuffInfo(buff->tblidx)
            }else{
                buff->dwTimeRemaining -= 2000;
            }
        }
    }
}

DelPcBuffInfo函数:

void CSkill::DelPcBuffInfo(unsigned int tblidx)
{
    p_BuffInfo.erase(tblidx);
}

DelPcBuffInfo执行后,程序崩溃了。

在这一行崩溃:

sBUFF_INFO* buff = it->second;

在调试时:

  

GameServer.exe中0x00578e0f处的未处理异常:0xC0000005:   访问冲突读取位置0xddddddd9。

it + node_ = hash_ CXX0030;错误:无法评估表达式

我真的不明白为什么会出现这个错误..

编辑: 如果我在此之后添加“返回” - &gt; DelPcBuffInfo(buff-&gt; tblidx),那么程序不会崩溃..

4 个答案:

答案 0 :(得分:2)

在容器中添加或删除项通常会使迭代器失效。查看unordered_map迭代器的文档或此处:Iterator invalidation in boost::unordered_map

答案 1 :(得分:1)

正确的习语是

for( itertype(p_BuffInfo) it = p_BuffInfo.begin(); it != p_BuffInfo.end(); )
{
    sBUFF_INFO* buff = it->second;
    if(buff != NULL)
    {
        if(buff->dwTimeRemaining <= 0)
        {
            it = this->DelPcBuffInfo(buff->tblidx)
        }else{
            buff->dwTimeRemaining -= 2000;
            it++;
        }
    }
}

即不要在循环中递增。如果你不删除则增加,否则让删除操作返回新的迭代器。这就是为什么remove会返回一个指向下一个元素的迭代器

这是由令人敬畏的斯科特迈尔斯提供的

答案 2 :(得分:1)

添加到指出erase-iterator惯用语的现有答案:崩溃的原因是迭代器it由于删除了元素而失效。因此,(无效)运算符的增量会导致未定义的行为,并且它将指向某个任意的内存块。取消引用&#34;迭代器&#34;然后崩溃你的程序。

要避免此问题,请应用其他答案中所示的习语,即  *使用erase的迭代器版本。它返回 next 元素的迭代器(可能是end())  *使用此erase的返回值作为it的新值。由于它已指向下一个元素,因此 not 再次递增(否则,如果it已指向地图的末尾,则可能会跳过地图中的元素或导致未定义的行为。  *当你擦除元素时,只自己增加迭代器。

注意:如果您打算在从地图中删除后完全删除sBUFF_INFO元素,那么您的程序会显示内存泄漏。从地图中删除指针不会删除指向的内存。您需要自己删除指针(或使用适当的智能指针)。

答案 3 :(得分:0)

void CSkill::DecreaseAllBuffRemTime()
{
    auto it = p_BuffInfo.begin();
    while( it != p_BuffInfo.end() )
    {
        sBUFF_INFO* buff = it->second;
        if(buff)
        {
            if(buff->dwTimeRemaining <= 0)
            {
                // probably delete buff too
                it = p_BuffInfo.erase(it);
            } else {
                buff->dwTimeRemaining -= 2000;
                ++it;
            }
        } else {
            ++it;
        }
    }
}