Lambda 和 std::function 导致悬空引用(分段错误)

问题描述 投票:0回答:1

我有一个实体系统(我尝试重新创建一个更简单的ECS,而不必担心内存放置...)

实体管理器:

class EntityManager
{
    std::unordered_map<std::type_index, std::list<mia::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) {
                if (!entity->IsActive()) continue;

                // Here the std::function call
                method(dynamic_cast<T*>(entity));
            }
        }
    }
}

实体

class Entity
{
    Entity::Entity(std::type_index type)
    {
        EntityManager::RegisterEntity(type, this);
    }
}

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()
{
    ObjA *a0 = new ObjA(0);
    EntityManager::IterateEntities<DerivedEntity>([](DerivedEntity* t) { t->Notify(); });
}

我认为问题是悬空引用,因为我尝试在 Notify() 中记录地址,它返回 null

void Notify()
{
    printf("Log: %p", this); // Log
    printf("Notitied: %d", id);
}

当我在 std::function 调用之前记录实体时,它返回我正在寻找的正确对象

printf("Log: %p", entity); // Log
method(dynamic_cast<T*>(entity));

如何解决?

c++ lambda segmentation-fault dangling-pointer
1个回答
0
投票

我无法立即找到一个很好的副本,所以我会正确回答。

Entity
不是 多态,因为它没有任何虚拟方法。

您可以从文档中看到,

dynamic_cast
仅适用于当源是多态时的向下转换(您想要执行的操作)。

您可以并且应该通过在

dynamic_cast
中编写一个简单的
main
来确认这是您的问题。在调试器(使用调试版本)中检查分段错误也会让您了解这个
nullptr
来自何处。

只需添加虚拟析构函数即可使

Entity
成为多态。如果您可能想使用基类指针来管理所有权,那么您通常应该拥有其中之一。

© www.soinside.com 2019 - 2024. All rights reserved.