我正在遵循游戏对象架构的设计presented by Marcin Chady 。 简而言之,游戏对象类可以包含多个属性和行为子类实例。游戏对象也包含在 Scene 类中。该图可以澄清一些事情:
行为子类需要能够访问其父游戏对象类。这是必需的,因为行为需要能够读取和写入各种属性并订阅以接收来自游戏对象的事件。某些行为可能还需要访问其父游戏对象的场景,以便它们可以实例化其他游戏对象。
我目前正在使用共享指针和弱指针。例如,游戏对象类包含 vector<shared_ptr<Attribute>>
和vector<shared_ptr<Behaviour>>
。行为和属性类都包含 weak_ptr<GameObject>
。这打破了引用循环。
现在,如果一个行为想要访问场景,它需要执行一些嵌套的弱指针锁:
if (std::shared_ptr<GameObject> sharedGameObject = GetGameObject().lock())
{
if (std::shared_ptr<Scene> sharedScene = sharedGameObject->GetScene().lock())
{
// Do something with the scene.
}
}
这可能会变得有点困惑。如果我们需要访问 Application 类,则需要 3 个嵌套锁。使用原始指针时显然不需要这样做。我使用的智能指针正确吗?如果是的话,我能做些什么来解决这个问题,还是我只能忍受这种情况?
最佳答案
你真的想要这里的智能指针吗?从第一个猜测来看, 基于设计层次结构(和名称):
如果这是一个典型的层次结构,则只有一个
Application
,不会动态分配,但会 是main
中的局部变量。所以永远不会有聪明人 指向它的指针。所有
Scene
都属于Application
,所以从设计上就很清楚 谁拥有什么。在这两种情况下,都是一对多的关系,即 意味着拥有对象中的指针需要位于 容器。您可以使用std::unique_ptr
,但它不会 看起来确实有必要;事实上,这似乎有点令人困惑: 要删除对象,您不使用delete
,而是将其erase
容器。 (另一方面,使用原始指针,您可以 必须将其从容器中删除和移除。它是 很大程度上取决于你,尽管我更喜欢简单 原始指针。)如果这些类代表了我认为它们所做的事情,
GameObject
由于外部事件而出现和消失。这是一个典型的 现有智能指针都不相关的情况。 我猜想大部分GameObject
都是由 响应事件的场景
;有些可能是由其他人创建的游戏对象
。但一旦创建,它们就会管理自己的生命周期, 并且可能会被他们事件中的delete this
删除 处理程序。 (当然,所有对其生命周期感兴趣的对象 必须使用观察者模式注册为观察者。 但无论如何,情况都会如此。)EventDispatcher
无疑具有指向任何对象的指针 对事件感兴趣,但这些是为了导航。他们应该 不是是智能指针。这是每个人的责任 使用EventDispatcher
注册和取消注册的对象 根据它感兴趣的事件——而不是 显然,它将取消析构函数中的所有内容, 因为死亡对象对任何事件都不感兴趣,但它 还将(可能)在其他不同时间注册和取消注册 也是如此。
请注意,weak_ptr
的必要性通常是好的
表明引用计数指针不是解决方案
您正在寻找。
关于使用智能指针的 C++ 组合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20077778/