【问题标题】:Simple, efficient weak pointer that is set to NULL when target memory is deallocated释放目标内存时设置为 NULL 的简单、高效的弱指针
【发布时间】:2010-12-24 23:19:33
【问题描述】:

是否有一个简单、高效的弱/保护指针?我需要多个指向同一个对象的指针,这些指针在对象被删除时都自动设置为 NULL。有一个“主”指针始终用于删除对象,但可以有多个其他指针引用同一对象。

以下是一些不太符合我需求的解决方案:

  • QPointer:我不是在开发QT应用;我不希望包含来自 QObject 的这个库/派生。
  • boost::weak_ptr: 访问已释放对象时抛出异常。对我的情况来说太贵了:测试弱指针应该是正常的;当弱指针不再有效时,我计划进行一些手动清理。 更新:weak_ptr 可以在不抛出异常的情况下进行测试
  • Low-Overhead Weak Pointers:这与我正在寻找的非常接近,除了我不喜欢这样一个事实“这个方案只有在你不分配 2**sizeof(int) 时间的情况下才能保证工作在同一个位置。”

为什么我需要这些弱/受保护的指针: 我有一个带有游戏对象列表的游戏。一些对象依赖于其他对象,例如与游戏实体关联的调试/统计对象。调试/状态对象显示有关游戏实体的有用信息,但它仅在游戏实体存在时才有意义。所以如果游戏实体被删除,调试/统计对象应该意识到这一点并删除自己。 (另一个想法是跟踪导弹:它可能会搜索新目标,而不是自我删除。)

我希望将调试/统计逻辑与游戏实体分开。游戏实体不必知道附加了调试/统计对象。虽然我更喜欢弱/受保护的指针的答案,但我也欢迎以不同的方式来处理我的特定任务。我在想我可能必须实现一个 game object manager 来跟踪对象的生命周期并使用句柄而不是指向内存地址的原始指针。

我正在使用 C++ 进行开发。

【问题讨论】:

  • 一个普遍的问题是,“Qt 是开发游戏的正确选择吗?”
  • Boost 的弱指针允许你测试它是否有效。如果您直接尝试取消引用它,它只会引发异常 - 类似于尝试取消引用空指针时发生的情况。
  • C++11 有std::weak_ptr。看起来与 Boost 中的相似。

标签: c++ pointers dangling-pointer


【解决方案1】:

您可以使用boost::weak_ptrlock() 成员来测试(然后使用)weak_ptr 的值,而无需处理异常。

【讨论】:

  • c++11 出来了,可以看看 std::weak_ptr。
【解决方案2】:

这在游戏开发中很常见。通常使用对象句柄系统而不是 Boost 弱指针,因为我们需要底层查找表是常量内存,而且有时我们需要一些 Boost 没有的附加信息或保证。

通常的方法是对指向指针的指针进行详细说明。实体通过句柄而不是指针来引用。句柄是指向实体指针的大数组的索引。当一个实体死亡时,它会将其实体表中的指针清空。

struct handle_t
{
   uint32 serialnumber;  // this is a GUID for each entity; it increases 
                         // monotonically over the life of the process
   uint   entityindex;
   inline Entity *Get();
}

struct entityinfo_t
{
   Entity *pEntity;  // an entity's destructor NULLs this out on deletion
   uint32  serialnumber;
}

entityinfo_t g_EntityTable[MAX_ENTITIES];

Entity *handle_t::Get() 
{
  entityinfo_t &info = g_EntityTable[entityIndex];
  if ( serialnumber == info.serialnumber )  
  {
     return info.pEntity;
  }
  else
  {
      return NULL;
  }
}

序列号是必要的,因为数组的大小是恒定的——最终,您将需要回收实体表条目,并且您可能会存储一个句柄,例如索引 #743,该句柄足够长,以至于对象被删除,单元格 #743 被重新用于其他用途。如果您只是有一个指向指针列表的指针,您最终将拥有一个指向完全不同对象的句柄,而不是 NULL。因此,我们给每个实体一个全局唯一的编号,并将其存储在句柄中。

当然,您可以为实体表使用标准向量、映射或字典或其他类型的数据结构,但我们的要求通常是恒定内存、缓存一致性和绝对最大性能(因为 handle_t ::Get() 每帧被调用数千次)。

【讨论】:

    猜你喜欢
    • 2013-07-30
    • 2015-05-01
    • 2016-03-01
    • 2010-12-25
    • 2020-03-22
    • 2012-10-10
    • 2021-01-20
    • 2020-06-23
    • 1970-01-01
    相关资源
    最近更新 更多