如何为生存时间少于对象所有者的类组织对象所有权?



我有以下情况:有GraphicsContext类:

class GraphicsContext {
...
private:
std::unique_ptr<Renderer> m_renderer;
}

还有一类应用程序使用 GraphicsContext:

class Application {
...
private:
std::unique_ptr<GraphicsContext> m_graphicsContext;
}

还有一些子级类在应用程序类中使用,这些子级类使用来自 GraphicsContext 的渲染器。我需要在这些类中存储指向渲染器的指针,但是我应该怎么做呢?

class SubLevelClass {
public:
SubLevelClass(Renderer* renderer);
...
void drawSomething();
private:
Renderer* m_renderer; // this class is not owner of Renderer but should can ability to refer to it
}

这样的子级类在语义上并不拥有渲染器,因此我认为使用 shared_ptr 而不是 unique_ptr 并不是一个好主意。但是,如果保证子级类的对象比应用程序对象的生存时间短,如何组织这种所有权?我可以存储并从 GraphicsContext 返回指向渲染器的原始指针还是语义错误的想法?

有一些方法可以解决这个问题。

这些代码未经测试,但应该足以显示这个想法。

解决方案1:保持跟踪

解决方案 1A :-

class Renderer{
std::vector<SubLevelClass*> whoThatLinkBackToMe; //or std::unordered_set
public: ~Renderer(){
//assert that whoThatLinkBackToMe.size() == 0
}
};
class SubLevelClass{
SubLevelClass(Renderer* renderer){
renderer->whoThatLinkBackToMe.push_back(this);
}
//.. destructor should remove "this" from "renderer->whoThatLinkBackToMe" too
};

解决方案 1B :-

class CentralizeSystem{
public: static std::unordered_map<Renderer*,SubLevelClass*> map;
};
class Renderer{
public: ~Renderer(){
//assert that CentralizeSystem::map[this].size() == 0
}
};
class SubLevelClass{
SubLevelClass(Renderer* renderer){
CentralizeSystem::map.add(renderer,this);
}
//.. destructor should remove "this" from "CentralizeSystem::map" too
};

解决方案 2:实体组件系统 (ECS)

这是一场设计革命,需要巨大的承诺:-

  1. 使Renderer成为 ECS 中的系统。因此,它最后会自动删除。
  2. 使SubLevelClass成为 ECS 中的组件。 尝试将所有信息(字段、缓存)存储在SubLevelClass中 - 而不是Renderer. 仅这两件事就可以解决您的问题。
  3. 但是,如果它非常不幸,例如您需要使Renderer不是单例(成为组件):

    3.1 创建一个新组件Component_CheckDelete例如:-

    class Component_CheckDelete : public Component{
    public: bool ToBeDeleted=false;
    };
    

    3.2 每当要删除Renderer时,只需标记其Component_CheckDelete::ToBeDeleted=true即可。
    然后,在时间步长结束时,检查SubLevelClass的每个实例。
    如果有一些SubLevelClass引用了convertToComponent<Component_CheckDelete>(rendererPtr)->ToBeDeleted==trueRenderer,则抛出断言失败。

解决方案 3

只是忽略整个问题。
这是用户端的错误。 引擎创建者不应该抓住每个用户的错误。

Bullet Physics(最好的物理引擎之一)经常使用这种方法 - 如果我删除它的板相模块并仍然使用其主引擎,我可能会得到不负责任的访问违规。

的意见:我通常选择解决方案3,有时选择解决方案2,很少选择解决方案1A。

恕我直言,std::shared_ptr是正确的解决方案。

这样的子级类在语义上并不拥有渲染器,因此我认为使用shared_ptr并不是一个好主意

如果子级类需要延长Renderer对象的生存期以匹配自己的对象,则它们共享该对象的所有权。

相关内容

  • 没有找到相关文章

最新更新