我在使用此代码时出现错误:
for(std::vector<AguiTimedEvent*>::iterator it = timedEvents.begin();
it != timedEvents.end();)
{
if((*it)->expired())
{
(*it)->timedEventCallback();
delete (*it);
it = timedEvents.erase(it);
}
else
it++;
}
可能是什么问题?
定时事件有时会在调用其回调时推送一个新的,可能会这样做
由于
答案 0 :(得分:7)
如果循环遍历向量并且回调函数导致向量被添加到,则向量中的所有迭代器都可能无效,包括循环变量it
。
在这种情况下(回调修改向量)你可能最好使用索引作为循环变量。
您可能需要对设计进行一些全面的分析,以确保您不会创建任何意外的无限循环。
E.g。
for(std::vector<AguiTimedEvent*>::size_type n = 0;
n < timedEvents.size();)
{
if(timedEvents[n]->expired())
{
timedEvents[n]->timedEventCallback();
delete timedEvents[n];
timedEvents.erase(timedEvents.begin() + n);
}
else
n++;
}
答案 1 :(得分:3)
定时事件有时会在调用其回调时推送一个新的,可能会这样做
是
如果向向量添加元素,it
可能会失效。
答案 2 :(得分:1)
编辑:
定时事件有时推新 一个在调用它的回调时, 可能会这样做
是的,这绝对不安全。如果向量必须调整大小,那么它的所有指针和迭代器都将失效。你永远不应该插入到向量的中间,而它会被迭代,这将导致死亡。也许如果你转换成数字for循环,问题就会解决。
答案 3 :(得分:1)
听起来像是std::remove_copy_if
和std::remove_if
的工作:(没有对此进行过测试,但它应该会给你这个想法......)
#include <algorithm>
#include <functional>
//I'm sure you probably already have a delete functor lying around, right?
// No? Well here's one for you....
struct Deleter : public std::unary_function<AguiTimedEvent*, void>
{
void operator()(AguiTimedEvent* toNuke)
{
delete toNuke;
}
};
std::vector<AguiTimedEvent*> toRun;
std::remove_copy_if(timedEvents.begin(), timedEvents.end(),
std::back_inserter(toRun), std::not1(std::mem_fun(&AguiTimedEvent::expired)));
timedEvents.erase(std::remove_if(timedEvents.begin(), timedEvents.end(),
std::mem_fun(&AguiTimedEvent::expired), timedEvents.end());
std::for_each(toRun.begin(), toRun.end(),
std::mem_fun(&AguiTimedEvent::timedEventCallback));
std::for_each(toRun.begin(), toRun.end(), Deleter());
请注意,此解决方案需要线性时间,而您的解决方案需要四倍时间。这也彻底解决了回调可能添加到新向量的问题,通过删除有关该向量的决定,直到从向量中删除之后为止。另一方面,它检查expired
标志两次,所以如果这是一个复杂的操作,这可能会更慢。