【问题标题】:Memory Management Design内存管理设计
【发布时间】:2013-07-02 03:53:08
【问题描述】:

我在为实体组件系统设计内存管理时遇到了一些问题,并且在设计细节方面遇到了一些问题。这是我想要做的(请注意,除了Entity 之外的所有这些类实际上都是虚拟的,因此会有许多不同的具体实现):

Program 类将有一个 Entity 的容器。 Program 将循环通过Entity 并在每个上调用更新。它还会有几个SubSystem,它还会在每个循环中更新。

每个Entity 将包含两种类型的Component。它们都将由Entity 内的unique_ptr 拥有,因为它们的生命周期与实体直接相关。一种类型,UpdateableComponent,将在调用Entity.update() 方法时更新。第二种类型SubSystemComponent 将从它们各自的SubSystem 中更新。

现在这是我的两个问题。首先是一些Component 将控制其父Entity 的生命周期。我目前对此的想法是Component 将能够调用函数parent.die(),这将更改Entity 中的内部标志。然后在Program 完成循环更新后,它会第二次循环并删除在上次更新期间标记为删除的每个Entity。我不知道这是否是一种有效或聪明的方法,尽管它应该避免Entity 在其Component 仍在更新时死亡的问题。

第二个问题是我不确定如何从SubSystem 中引用SubSystemComponent。因为它们是由Entity 内部的unique_ptr 引用的,所以我不能使用shared_ptrweak_ptr,并且当拥有组件的Entity 死亡时,标准指针最终会悬空。我可以为这些切换到Entity 中的shared_ptr,然后在SubSystem 中使用weak_ptr,但是我不想这样做,因为重点是Entity 完全拥有它Component 的。

所以两件事:

  • 能否以有意义的方式改进我的第一个想法?
  • 有没有一种简单的方法可以用unique_ptr 实现weak_ptr 类型的功能,或者我应该切换到shared_ptr 并确保不要创建多个shared_ptrSubSystemComponent' s

【问题讨论】:

  • 我认为你可能想对内存管理做更多的研究,除非你对这个设计死心塌地;多次循环遍历整个分配的内存空间将不可扩展。智能指针始终是一种很好且简单的初始启动方式。此外,已经有一些完善的 C++ 库可以执行garbage collection
  • @Aggieboy 我已经考虑过缩放问题,并且已经解决了仅将部分数据加载到 Entity 的问题,这将我限制在几千个(最多可能 10-20 个)一次。如果我简单地调用一个 bool getter,并且可以选择从容器中删除Entity,那么第二个循环真的会那么低效吗?这样的设计更多是为了提高代码的复用性而不是性能,后期我可以轻松优化瓶颈。
  • 您可以在尝试更新组件之前简单地检查hasToDie 标志,这不是问题。但是,unique_ptrs 明确设计用于单一、严格的所有权。只要不止一个对象需要引用(保证始终有效或至少可检查),您就不会超过 shared_ptr 和可能的 weak_ptr,正如您已经指出的那样。
  • @arne 我在更新循环期间检查的一个问题是想象更新检测到冲突。第一个实体将能够与“死”对象发生碰撞,而最后一个实体则不会。虽然,如果我首先循环更新,检查死亡,然后进行子系统更新,其中包括碰撞之类的交互。 . .也许这会简化它。

标签: c++ memory-management


【解决方案1】:

能否以有意义的方式改进我的第一个想法?

如果不了解所进行工作的性质,很难说。例如,您没有提及您对线程的使用,但您的设计似乎通过按设定的顺序循环处理所有可能的更新,从而对所有可能的更新给予同等优先级。对于一些低延迟很重要的事情,或者理想情况下可以完成一些有用的优先级排序,这样的循环序列并不好,而在其他时候它是理想的。

还有其他方法可以协调组件驱动从程序中删除实体:

  • 返回代码可能会冒泡到实体的循环中,从而触发实体容器的擦除,
  • 观察者模式或 lambda/std::function 可以允许程序指定清理行为。

有没有一种简单的方法可以用 unique_ptr 来实现一个weak_ptr 类的功能,

没有。

或者我应该切换到 shared_ptr 并确保不要为 SubSystemComponent 创建多个 shared_ptr

这听起来很合适。您甚至可以将 shared_ptr 包装在不可复制的类中以避免意外错误。

或者 - 至于上面的实体销毁 - 您可以使用事件协调 SubSystemSubSystemComponent 之间的链接,因此 SubSystemComponent 析构函数回调到 SubSystem。观察者模式是执行此操作的一种方法,SubSystemComponent-side std::function 馈送 lambda 更加灵活。无论哪种方式,Subsystem 都会从其记录中删除 SubSystemComponent

【讨论】:

    猜你喜欢
    • 2019-10-03
    • 2013-09-25
    • 1970-01-01
    • 1970-01-01
    • 2011-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多