2

我一直在努力解决一个相当令人费解的问题:当我的实体管理器在更新循环中遍历实体映射时,我偶尔会遇到分段错误。奇怪的是,这种情况并非一直发生。有时它会在加载时崩溃,有时我可以在出现段错误之前在应用程序状态(以及多次加载和卸载实体)之间切换几次。在调试模式下,我似乎也遇到了更多的段错误。我的实体由指向 Behavior 和 Drawable 类的指针组成。

段错误后我的调用堆栈:

#0 6FCB4986 libstdc++-6!_ZSt18_Rb_tree_incrementPSt18_Rb_tree_node_base() (C:\MinGW\bin\libstdc++-6.dll:??)
#1 0040A1D7 std::_Rb_tree_iterator<std::pair<unsigned int const, Entity*> >::operator++(this=0x28fe94) (c:/mingw/bin/../lib/gcc/mingw32/4.6.2/include/c++/bits/stl_tree.h:196)
#2 00401F55 EntityManager::onLoop(this=0x417238) (C:\Users\Nelarius\Documents\Kurssit\Miinaharava\src\engine\EntityManager.cpp:75)
#3 00401640 App::onLoop(this=0x417040) (C:\Users\Nelarius\Documents\Kurssit\Miinaharava\src\engine\App.cpp:38)
#4 0040160C App::execute(this=0x417040) (C:\Users\Nelarius\Documents\Kurssit\Miinaharava\src\engine\App.cpp:30)
#5 00403BD7 main(argc=1, argv=0x642908) (C:\Users\Nelarius\Documents\Kurssit\Miinaharava\src\main.cpp:15)

这是我的更新循环:

void EntityManager::onLoop()
{
    std::map<const unsigned int, Entity*>::iterator it;

    for (it = _gameObjects.begin(); it != _gameObjects.end(); it++)
    {
        Behavior* behavior = it->second->getBehavior();
        if (behavior)
        {
            behavior->update();
        }
    }
}

我得到了段错误

for (it = _gameObjects.begin(); it != _gameObjects.end(); it++)

顺便说一句,当我不使用任何多线程时,有两个线程是否正常?我正在查看Code::Blocks调试窗口,并且碰巧看到线程监视窗口中有两个线程(尽管其中只有一个处于活动状态)。

4

2 回答 2

2

通常这种事情归结为behavior->update()能够通过一系列嵌套函数调用在_gameObjects被修改的容器中产生结果(例如,如果在游戏对象中检测到的某些条件导致创建或删除游戏对象原因)。

如果您从 中删除了一个元素,这可能会使您的迭代器无效并中断您的循环map,并且很难在这样的“内核”代码中发现。

一个常见的解决方案是为循环复制游戏对象列表。当然,您不会复制对象本身,但您正在保护它们的列表不致在更新运行过程中发生变异。

它在调度方面也“更公平”——你基本上避免了由心怀不满的自我复制游戏对象发起的 DDoS 攻击的可能性。:)

于 2013-01-28T13:45:55.030 回答
0

您正在迭代非本地数据,然后调用非本地函数。

创建本地地图。 swap类映射到它。迭代该本地地图。断言迭代完成后类映射未更改(您还需要断言从类映射中删除内容的所有尝试都成功)。

然后将本地地图交换回班级的地图。

这将告诉您您的崩溃是否是由您的不良设计引起的。即使没有生成任何断言,该设计仍然存在问题,因为远离上述代码的无害代码更改可能会导致发生上述问题:代码正确性的非局部性会导致问题。通过充分的测试,可以容忍带有断言的代码正确性的非局部性。

一般的回调问题需要您对注册回调的含义做出妥协,并涉及以类似于多线程代码的方式思考问题。如果您不愿意妥协,代码复杂性会变得非常高。建议使用智能指针来简化事情。

于 2013-01-28T13:37:40.260 回答