代码之家  ›  专栏  ›  技术社区  ›  Leftium

简单、高效的弱指针,在解除分配目标内存时设置为NULL

  •  8
  • Leftium  · 技术社区  · 16 年前

    我需要多个指向同一对象的指针,当删除该对象时,这些指针都会自动设置为NULL。有一个“主”指针始终用于删除对象,但也可以有多个其他指针引用同一对象。

    以下是一些与我的需求不太匹配的解决方案:

    • QPointer :我没有开发QT应用程序;我不希望包含此库/源于QObject。
    • boost::weak_ptr : 访问解除分配的对象时引发异常。对于我的情况来说太贵了:测试弱指针应该是正常的;我计划在弱指针不再有效时进行一些手动清理。 :弱ptr可以在不引发异常的情况下进行测试
    • Low-Overhead Weak Pointers

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

    我希望将调试/统计逻辑与游戏实体分开。游戏实体不必知道已附加调试/统计对象。虽然我更喜欢弱/保护指针的答案,但我也欢迎不同的方法来完成我的特定任务。我想我可能必须实施一个 game object manager

    我正在用C++开发。

    2 回复  |  直到 8 年前
        1
  •  17
  •   Michael Burr    16 年前

    你可以使用 lock() boost::weak_ptr weak_ptr 不处理例外情况。

        2
  •  10
  •   Crashworks    16 年前

    这是游戏开发中常见的事情。通常使用对象句柄系统,而不是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重新用于其他用途。如果您只是有一个指向指针列表的指针,那么最终会有一个指向完全不同对象的句柄,而不是空的。因此,我们给每个实体一个全局唯一的编号,并将其存储在句柄中。

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