C++ 向量迭代器不可解引用?

C++ 向量迭代器不可解引用?,c++,stl,vector,iterator,C++,Stl,Vector,Iterator,我得到了这个错误的代码: for(std::vector<AguiTimedEvent*>::iterator it = timedEvents.begin(); it != timedEvents.end();) { if((*it)->expired()) { (*it)->timedEventCallback(); delete (*it); it = timedEvents.erase(it

我得到了这个错误的代码:

for(std::vector<AguiTimedEvent*>::iterator it = timedEvents.begin();
    it != timedEvents.end();)
{
    if((*it)->expired())
    {
        (*it)->timedEventCallback();
        delete (*it);

        it = timedEvents.erase(it);
    }
    else
        it++;
}
for(std::vector::iterator it=timedEvents.begin();
it!=timedEvents.end();)
{
如果((*it)->expired())
{
(*it)->timedEventCallback();
删除(*它);
它=timedEvents.erase(它);
}
其他的
it++;
}
有什么问题吗


定时事件有时在调用其回调时推入一个新事件,这可能会完成

谢谢

编辑:


定时事件有时会推送一个新的 当调用其回调时, 那也许行

是的,那绝对是不安全的。如果向量必须调整大小,那么它的所有指针和迭代器都将无效。当向量被迭代时,你永远不应该插入到向量的中间,这会导致死亡。也许如果你转换成一个数值for循环,问题就解决了


定时事件有时在调用其回调时推入一个新事件,这可能会完成


如果将元素添加到向量中,
它可能会失效。

如果在向量中循环,并且回调函数导致向量被添加到,则向量中的所有迭代器都可能失效,包括循环变量
it

在这种情况下(回调修改向量),最好使用索引作为循环变量

您可能需要对设计进行彻底的分析,以确保不会创建任何意外的无限循环

例如

for(std::vector::size_type n=0;
nexpired())
{
timedEvents[n]->timedEventCallback();
删除timedEvents[n];
timedEvents.erase(timedEvents.begin()+n);
}
其他的
n++;
}

听起来像是
std::remove\u copy\u if
std::remove\u if
:(还没有测试过,但它应该会给你一个想法……)

#包括
#包括
//我相信你可能已经有了一个删除函子,对吧?
//没有?嗯,这是给你的。。。。
struct Deleter:public std::一元函数
{
void运算符()(AguiTimedEvent*toNuke)
{
删除toNuke;
}
};
std::矢量环;
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(&aguitimedeventcallback::timedEventCallback));
std::for_each(toRun.begin()、toRun.end()、Deleter());

请注意,此解决方案需要线性时间,而您的解决方案需要四次方时间。这也很好地解决了回调可能会添加到新向量的问题,方法是在从向量中删除之前删除关于此问题的决定。另一方面,它会两次检查
expired
标志,因此如果这是一个complex操作这可能较慢。

确切的错误文本是什么?表达式:向量迭代器不可解引用(调试断言失败)
timedEventCallback
AguiTimedEvent
的析构函数是否直接或间接地修改了
timedEvents
?定时事件有时在调用其回调时推入一个新的回调,如果您在迭代集合时(使用回调)修改集合,则可能会这样做,无法保证迭代器在之后仍然有效。这可能是您的问题。我可能很笨,但为什么它不安全?
被替换为返回值
擦除
结束()
在每次循环迭代中都会重新计算。@user470379:我可以阅读你在另一个答案上的注释,你知道。如果它像刚才那样被删除,我就看不到了;)@user470379:非常确定,由于有超过10000个代表,我可以查看已删除的答案及其相关注释。至于erase()的安全性,那么我同意你的看法——我也看不出它是如何无效的。然而,OP的代码中绝对没有其他错误源,这是一个非常简单的循环,因此除非你想让我断定他的STL实现或编译器存在缺陷,否则只有一件事需要注意。仅仅因为你有超过10k的代表,并不意味着每个人都会看到答案/评论。但是,现在你已经完全重写了答案,原来的评论就不需要了。@Milo:那要看你希望结果是什么了。向量中添加的新元素在哪里?您也要迭代它们吗?可能是在删除过程中将元素添加到容器中。@Milo,将元素推到临时向量上,并在循环完成后将其合并到主向量中。@Mark,@Milo:或者使用
deque
而不是
向量。添加到
deque
不会使早期迭代器失效。那么如何删除过期的元素?
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++;
}
#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());