我有一个Engine类,它包含并拥有一些系统。 Engine类有两个容器,一个映射和一个向量。两者都保持指向系统的指针。
addSystem模板函数应在地图中添加所需类型的新系统的指针,addToPipeline应添加作为向量中的参数传递的系统的指针。我使用了shared_ptrs但是我做错了,因为如果我使用addToPipeline函数,我会得到一个双重自由错误。
这是简化的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);
感谢任何帮助!
答案 0 :(得分:4)
在这一行:
m_pipeline.push_back(std::shared_ptr<System>(&sys));
您正在为已经管理的对象创建shared_ptr
,因为您已将同一对象包装在另一个智能指针中。因此,您最终会得到同一个对象的两个引用计数,因此您可以获得双倍的免费。
这不是shared_ptr
的使用方式。相反,您应该从shared_ptr
返回addSystem
并将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
(除非所有权不重要 - 然后您也可以传递引用)。你必须这样做,因为引用计数器由智能指针管理。
编辑:正如rozina指出的那样:当然,只要没有人试图删除相应的地址,您仍然可以传递对托管对象的引用。如果其他代码对使用某个对象感兴趣但不关心所有权,这实际上可能更好。例如,您可能希望拥有一个公共接口,该接口允许获取对内部由智能指针管理的某个对象的引用。例如:
class Foo {
public:
Bar& getBar() {
return *m_bar;
}
private:
std::shared_ptr<Bar> m_bar;
};
只要没有人delete &aFoo.getBar()
,这就完全没问题 - 如果您使用该引用创建新的shared_ptr
,就会发生这种情况,就像您在原始代码中所做的那样。