向量迭代器不可解引用?

发布于 2024-10-08 20:25:03 字数 383 浏览 1 评论 0原文

我收到此代码的错误:

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

        it = timedEvents.erase(it);
    }
    else
        it++;
}

可能是什么问题?

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

谢谢

I'm getting that error with this code:

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

        it = timedEvents.erase(it);
    }
    else
        it++;
}

What could be the problem?

the timed event sometimes pushes a new one in when its callback is called, that might do it

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

迷爱 2024-10-15 20:25:03

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

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

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

例如

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++;
}

If you are looping through a vector and the callback function causes the vector to be added to, then all iterators into the vector may be invalidated including the loop variable it.

In this case (where the callback modifies the vector) you are probably better off using an index as your loop variable.

You probably need to do some thorough analysis of the design to make sure that you aren't going to create any unexpected infinite loops.

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++;
}
一抹微笑 2024-10-15 20:25:03

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

如果向向量添加元素,可能会失效。

the timed event sometimes pushes a new one in when its callback is called, that might do it

Yes.

If you add an element to the vector, it may be invalidated.

戈亓 2024-10-15 20:25:03

编辑:

定时事件有时会推送新的
当它的回调被调用时,
这可能会做到

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

Edit:

the timed event sometimes pushes a new
one in when its callback is called,
that might do it

Yes, that is very definitely unsafe. If the vector has to resize, then all of it's pointers and iterators would be invalidated. You should never, ever insert into the middle of a vector whilst it's being iterated through, that will cause death. Maybe if you converted to a numerical for loop, the problem would be solved.

那支青花 2024-10-15 20:25:03

听起来像是 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 标志,因此如果这是一个复杂的操作,则可能会更慢。

Sounds like a job for std::remove_copy_if and std::remove_if: (Haven't tested this but it should give you the idea...)

#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());

Note that this solution takes linear time, while yours takes quadradic time. This also cleanly gets rid of the issue that the callbacks might add to the new vector by removing the decisions about that until after the removal from the vector has already been done. On the other hand, it checks the expired flag twice, so if that's a complex operation this might be slower.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文