矢量迭代器不是dereferencable?

时间:2010-12-21 23:19:40

标签: 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);
    }
    else
        it++;
}

可能是什么问题?

定时事件有时会在调用其回调时推送一个新的,可能会这样做

由于

4 个答案:

答案 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_ifstd::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标志两次,所以如果这是一个复杂的操作,这可能会更慢。