我有一个问题,不知道如何正确解决它或为什么出现错误。
对我的问题: 我有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),那么程序不会崩溃..
答案 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;
}
}
}