【问题标题】:Read access violation when inserting into unordered map插入无序映射时读取访问冲突
【发布时间】:2021-05-05 21:57:55
【问题描述】:

我在搞乱a small ECS implementation found here。我慢慢复制代码来理解它,它工作正常。但是,在尝试添加 ECS 的“系统”部分之前,我尝试将功能分离到不同的类中,并使用“协调器”类抽象所有内容,而不是一个大的命名空间。

所以我有这样的东西(对不起,如果我的代码提前不好,还在学习C++):

// ECSCoordinator.h

#ifndef I3D_ECS_COORDINATOR_H
#define I3D_ECS_COORDINATOR_H

#include <memory>
#include "Entity.h"
#include "EntityManager.h"

#include "ComponentContainer.h"

class ECSCoordinator {
public:
    ECSCoordinator();

    Entity create_entity();
    void delete_entity();

    template<typename Component>
    void add_component_to(Entity e, Component c);

private:
    template<class Component> 
    static ComponentContainer<Component> registry;
    std::unique_ptr<EntityManager> entity_manager;
};

template<typename Component>
void ECSCoordinator::add_component_to(Entity e, Component c) {
    registry<Component>.insert(e, c);
}

// ECSCoordinator.cpp

#include "ECSCoordinator.h"
#include "ECS/Entity.h"
#include "ECS/EntityManager.h"

ECSCoordinator::ECSCoordinator()
    : entity_manager(std::make_unique<EntityManager>()) {}

Entity ECSCoordinator::create_entity() {
    return entity_manager->create_entity();
}

#endif // I3D_ECS_COORDINATOR_H

我必须决定的一件事是在哪里声明registry。在最初的实现中,它是在命名空间的范围内声明的,但是一旦我将东西移动到类中,我不想让一个全局变量坐在那里。因此,我将变量模板设置为协调器的静态类成员。我相信这些是等价的?然后ComponentContainer 的前向声明不再起作用,因为我在标题中定义add_component_to,所以我不得不改为#include "ComponentContainer.h",这意味着我必须将ComponentContainer 中的静态定义移动到他们自己的.cpp 文件中(如果这很重要)。

除此之外,使 Entity.h 成为 POD(仅包含一个无符号整数)和 EntityManager.h 负责创建具有递增 ID 的实体,我没有太大变化。

所以当我想使用系统时,我想这样做:

std::unique_ptr<ECSCoordinator> coordinator = std::make_unique<ECSCoordinator>();
Entity fish = coordinator->create_entity();
coordinator->add_component_to(fish, Animal("Fish"));

但是,当我尝试将 (key, value) 添加到无序映射(tiny_ecs.hpp 的第 100 行)时,这些更改会导致读取访问冲突:

map_entity_component_index[e.id] = component_index;

我可以肯定地确认e.id = 0component_index = 1 是第一次添加。我可以在这个错误之前在无序映射上运行一个方法,比如size()。但是,尝试向地图添加内容会导致崩溃。

我不确定如何解释我在调试器中看到的错误:

感谢任何提供帮助的人。

【问题讨论】:

  • 什么是map_entity_component_index?它是在哪里定义的?
  • tiny_ecs.hpp 第 100 行的评论看起来有点麻烦:map_entity_component_index[e.id] = component_index; // Note, not using insert or emplace to allow inserting multiple components for the same entity (at your own risk) - 我想知道“风险自负”是什么意思。
  • @1201ProgramAlarm map_entity_component_index 是 ComponentContainer 继承自的类中的受保护成员。
  • 它没有在任何地方定义,但是,它只是被声明了。在原始实现中。通过调用registry&lt;ComponentClass&gt;.insert(entity, component),即registry&lt;WaterAnimal&gt;.insert(fish, WaterAnimal()),将某个实体的组件添加到注册表。我相信这隐含地实例化了registry&lt;WaterAnimal&gt;,其中一个指针保存在第 76 和 77 行(因为注册表的类型为ComponentContainer&lt;Component&gt;,而static std::vector&lt;ContainerInterface*&gt;(参见 tiny_ecs.cpp)是一个带有ComponentContainer 类指针的单例继承自)。

标签: c++ templates runtime-error


【解决方案1】:

答案最终是由于静态订单初始化惨败。解决方案是通过 getter 访问 Coordinator 中的静态模板变量,以确保其初始化:

class ECSCoordinator {
    //....

    template<class Component>
    ComponentContainer<Component>& get_registry();

    //...
};

template<typename Component>
void ECSCoordinator::add_component_to(Entity e, Component c) {
    get_registry<Component>().insert(e, c);
}

template<class Component>
ComponentContainer<Component>& ECSCoordinator::get_registry() {
    static ComponentContainer<Component> registry;
    return registry;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-15
    • 1970-01-01
    • 2017-12-09
    相关资源
    最近更新 更多