Lambda与std::function导致悬空引用(段错误)的修复方法咨询
问题描述
我实现了一个简易ECS实体系统(未过多考虑内存布局),运行时DerivedEntity的Notify函数触发段错误,在Notify中打印this指针显示为空,但调用std::function前打印entity地址是正确的,怀疑是悬空引用问题,相关代码如下:
EntityManager 代码
class EntityManager { static std::unordered_map<std::type_index, std::list<Entity*>> entitiesMap; public: static void RegisterEntity(std::type_index type, Entity* entity) { if (entitiesMap.find(type) == entitiesMap.end()) { entitiesMap.insert(std::pair<std::type_index, std::list<Entity*>>( type, std::list<Entity*>() )); } entitiesMap[type].push_back(entity); } template <class T> static void IterateEntities(std::function<void(T*)> method) { static_assert(std::is_base_of<Entity, T>::value, "T must be derived from Entity"); std::type_index type = std::type_index(typeid(T)); auto targetIterator = entitiesMap.find(type); if (targetIterator != entitiesMap.end()) { for (Entity* entity : targetIterator->second) { method(dynamic_cast<T*>(entity)); } } } }; std::unordered_map<std::type_index, std::list<Entity*>> EntityManager::entitiesMap;
Entity 代码
class Entity { public: Entity(std::type_index type) { EntityManager::RegisterEntity(type, this); } virtual ~Entity() = default; };
main.cpp 代码
class DerivedEntity : Entity { public: DerivedEntity(int s) : Entity(typeid(DerivedEntity)) { id = s; } int id; void Notify() { printf("Notitied: %d", id); // <--- Segmentation fault } }; int main() { DerivedEntity *test = new DerivedEntity(0); EntityManager::IterateEntities<DerivedEntity>([](DerivedEntity* t) { t->Notify(); }); }
问题原因
核心问题是私有继承:C++中类默认的继承方式是私有继承(class DerivedEntity : Entity等价于class DerivedEntity : private Entity)。此时Entity是DerivedEntity的私有基类,dynamic_cast无法将Entity*安全转换为DerivedEntity*,会返回nullptr。当调用Notify时,实际上是对空指针解引用,导致段错误。
修复方案
将DerivedEntity的继承方式改为公有继承,确保基类和派生类之间的转换合法:
// 修改继承方式为public class DerivedEntity : public Entity { public: DerivedEntity(int s) : Entity(typeid(DerivedEntity)) { id = s; } int id; void Notify() { printf("Notitied: %d", id); } };
额外优化建议
- 可以在
Entity的构造函数中直接使用typeid(*this)获取实际类型,避免派生类手动传递typeid,减少出错概率:class Entity { public: Entity() { EntityManager::RegisterEntity(std::type_index(typeid(*this)), this); } virtual ~Entity() = default; }; // 派生类构造函数无需再传递typeid DerivedEntity(int s) : Entity() { id = s; } - 可以在
IterateEntities中添加空指针检查,避免后续调用空指针:for (Entity* entity : targetIterator->second) { T* derived = dynamic_cast<T*>(entity); if (derived != nullptr) { method(derived); } }
内容的提问来源于stack exchange,提问作者Miaan
相关产品推荐
相关产品推荐

