插入无序地图时读取访问冲突
Read access violation when inserting into unordered map
我在搞乱 a small ECS implementation found here。我慢慢地复制代码来理解它并且它工作正常。但是,在我尝试添加 ECS 的“系统”部分之前,我尝试将功能分成不同的 classes 并使用“协调器”class 抽象所有内容,而不是一个大的命名空间.
所以我有这样的东西(对不起,如果我的代码提前不好,还在学习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
。在最初的实现中,它是在命名空间的范围内声明的,但是一旦我将内容移入 classes 中,我就不希望有一个全局变量就在那里。因此,我将变量模板设为协调器的静态 class 成员。我相信这些是等价的? ComponentContainer
的前向声明不再起作用,因为我在 header 中定义了 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"));
但是,当我尝试将(键,值)添加到无序映射(tiny_ecs.hpp 的第 100 行)时,这些更改会导致读取访问冲突:
map_entity_component_index[e.id] = component_index;
我可以肯定地确认 e.id = 0
和 component_index = 1
是第一次添加。我可以 运行 无序地图上的一个方法,比如 size()
就在这个错误之前就好了。但是,尝试向地图添加内容会导致崩溃。
我不确定如何解释我在调试器中看到的错误:
感谢所有提供帮助的人。
答案最终是由于静态订单初始化失败。解决方案是通过 getter 访问协调器中的静态模板变量以确保其初始化:
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;
}
我在搞乱 a small ECS implementation found here。我慢慢地复制代码来理解它并且它工作正常。但是,在我尝试添加 ECS 的“系统”部分之前,我尝试将功能分成不同的 classes 并使用“协调器”class 抽象所有内容,而不是一个大的命名空间.
所以我有这样的东西(对不起,如果我的代码提前不好,还在学习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
。在最初的实现中,它是在命名空间的范围内声明的,但是一旦我将内容移入 classes 中,我就不希望有一个全局变量就在那里。因此,我将变量模板设为协调器的静态 class 成员。我相信这些是等价的? ComponentContainer
的前向声明不再起作用,因为我在 header 中定义了 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"));
但是,当我尝试将(键,值)添加到无序映射(tiny_ecs.hpp 的第 100 行)时,这些更改会导致读取访问冲突:
map_entity_component_index[e.id] = component_index;
我可以肯定地确认 e.id = 0
和 component_index = 1
是第一次添加。我可以 运行 无序地图上的一个方法,比如 size()
就在这个错误之前就好了。但是,尝试向地图添加内容会导致崩溃。
我不确定如何解释我在调试器中看到的错误:
感谢所有提供帮助的人。
答案最终是由于静态订单初始化失败。解决方案是通过 getter 访问协调器中的静态模板变量以确保其初始化:
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;
}