我正在遵循游戏对象架构presented by Marcin Chady的设计。 作为快速摘要,Game Object类可以包含多个Attribute和Behavior子类实例。游戏对象也包含在Scene类中。这个图表可以澄清一些事情:
Behavior子类需要能够访问其父Game Object类。这是必需的,因为行为需要能够读取和写入各种属性并订阅从游戏对象接收事件。某些行为可能还需要访问其父游戏对象的场景,以便他们可以实例化其他游戏对象。
我目前正在使用共享指针和弱指针。例如,Game Object类包含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个嵌套锁。使用原始指针时,这显然不是必需的。我使用正确的智能指针吗?如果我是,有什么我可以做的来整理这个或者这是我将要忍受的东西吗?
答案 0 :(得分:1)
我认为你根本不需要任何智能指针,假设:
GameObject
对象真正拥有 Attribute
&amp; Behavior
个对象或GameObject
对象的生命周期始终长于Attribute
&amp; Behavior
对象的生命周期。或者考虑一下您的代码示例,请考虑以下问题:else
节能做什么?他们会被处决吗?我认为答案是:“他们只做失败/错误检测和报告”,“不,我无法想象”。
如果你希望它是更现代的C ++外观,或原始指针或原始引用,你应该使用GameObject
切换到std::reference_wrapper<T>
类的内部引用。
答案 1 :(得分:1)
你真的想要智能指针吗?从第一次猜测, 基于设计层次结构(和名称):
如果这是典型的层次结构,则只有一个
Application
,不会动态分配,但会
是main
中的局部变量。所以永远不会聪明
指向它的指针。
所有Scene
都属于Application
,所以从设计中可以看出
谁拥有什么。在这两种情况下,它都是1到n的关系
意味着拥有对象中的指针需要在
容器。您可以使用std::unique_ptr
,但事实并非如此
真的很有必要;事实上,它似乎有点混淆:
要删除某个对象,请不要使用delete
,而是erase
容器。 (另一方面,使用原始指针,你可以
必须同时从容器中删除和删除它。它的
虽然我倾向于简单,但在很大程度上取决于你
原始指针。)
如果这些类代表了我的想法,GameObject
由于外部事件而来来去去。这是典型的
没有现有智能指针相关的情况。
我猜大多数GameObject
是由...创建的
Scene
以回应某个事件;有些可能是由其他人创造的
GameObject
。但一旦创建,他们管理自己的一生,
并且可能会在事件中被delete this
删除
处理程序。 (当然,所有对他们一生感兴趣的物品
必须使用观察者模式注册为观察者。
但无论如何都是如此。)
EventDispatcher
毫无疑问地指向任何对象
对事件感兴趣,但这些是用于导航。他们应该
不是智能指针。这是每个人的责任
使用EventDispatcher
注册和撤消的对象
根据它感兴趣的事件 - 而不是
很明显,它会解析析构函数中的所有内容,
因为死对象对任何事件都不感兴趣,但它
也将(可能)在其他时间注册和退出
同样。
请注意weak_ptr
的必要性通常是好的
指示引用计数指针不是解决方案
你正在寻找。