共享所有权双重免费错误



我有一个引擎类,其中包含并拥有一些系统。Engine类有两个容器,一个映射和一个向量。两者都保留了指向系统的指针。

addSystem模板函数应该在映射中添加一个所需类型的新System指针,addtoppipeline应该在vector中添加一个作为形参传递的System指针。我使用shared_ptrs,但我做错了,因为我得到一个双重免费错误,如果我使用addtoppipeline函数。

下面是简化后的Engine类:

class Engine
{
public:
        template <class T>
        T& addSystem();
        void addToPipeline(System&);
private:
        std::map<std::type_index, std::shared_ptr<System>> m_systems;
        std::vector<std::shared_ptr<System>> m_pipeline;
};

void Engine::addToPipeline(System& sys)
{
        m_pipeline.push_back(std::shared_ptr<System>(&sys));
}

template <class T>
T& Engine::addSystem()
{
        std::shared_ptr<T> system = std::make_shared<T>();
        auto inserted = m_systems.emplace(typeid(T),system);
        return static_cast<T&>(*(*inserted.first).second);
}

函数应该如下所示使用:

auto& POSITION_SYSTEM = engine.addSystem<PositionSystem>();
engine.addToPipeline(POSITION_SYSTEM);

任何帮助都是感激的!

这一行:

m_pipeline.push_back(std::shared_ptr<System>(&sys));

您正在为已经管理的对象创建shared_ptr,因为您已经将同一对象包装在另一个智能指针中。因此,对于同一个对象,最终会得到两个引用计数,因此可以获得double free。

这不是shared_ptr应该如何使用。相反,您应该从addSystem返回一个shared_ptr,并将其作为addToPipeline的参数:

void Engine::addToPipeline(std::shared_ptr<System> sys)
{
    m_pipeline.push_back(sys);
}

template <class T>
std::shared_ptr<T> Engine::addSystem()
{
    std::shared_ptr<T> system = std::make_shared<T>();
    m_systems.emplace(typeid(T),system);
    return system; // No need to use the return value of emplace
}

shared_ptr s的想法是,而不是使用裸指针或引用,你总是传递一个shared_ptr(除非所有权不重要-然后你也可以传递一个引用)。必须这样做,因为引用计数器是由智能指针管理的。

Edit:正如rozina指出的:当然你仍然可以传递对托管对象的引用,只要没有人试图删除相应的地址。如果其他代码对使用某个对象感兴趣,但不关心所有权,这实际上可能是可取的。例如,您可能希望有一个公共接口,它允许获取对内部由智能指针管理的某个对象的引用。例如:

class Foo {
public:
    Bar& getBar() {
        return *m_bar;
    }
private:
    std::shared_ptr<Bar> m_bar;
};

只要没有人使用delete &aFoo.getBar(),这是完全可以的——如果您使用该引用创建一个新的shared_ptr,就像您在原始代码中所做的那样。

相关内容

  • 没有找到相关文章

最新更新