You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 07:01:05