9

シンプルで効率的なウィーク/ガードポインターはありますか?同じオブジェクトへの複数のポインターが必要です。これらのポインターは、オブジェクトが削除されるとすべて自動的にNULLに設定されます。オブジェクトを削除するために常に使用される「マスター」ポインターが1つありますが、同じオブジェクトを参照する他のポインターがいくつかある場合があります。

これが私のニーズに完全に一致しないいくつかの解決策です:

  • QPointer:私はQTアプリを開発していません。このライブラリ/QObjectからの派生物を含めたくありません。
  • boost :: weak_ptr割り当て解除されたオブジェクトにアクセスすると例外がスローされます。私の状況には高すぎる:弱いポインタをテストするのは正常なはずです。弱いポインタが無効になったときに、手動でクリーンアップする予定です。 update:weak_ptrは、例外をスローせずにテストできます
  • 低オーバーヘッドの弱いポインタ:これは私が探しているものに非常に近いですが、「このスキームは、2 ** sizeof(int)回を割り当てない限り機能することが保証されています。同じ場所です。」

これらの弱い/保護されたポインタが必要な理由: ゲームオブジェクトのリストを含むゲームがあります。一部のオブジェクトは他のオブジェクトに依存しています。たとえば、ゲームエンティティに関連付けられているdebug/statsオブジェクトです。debug / statusオブジェクトは、ゲームエンティティに関する有用な情報を表示しますが、ゲームエンティティが存在する場合にのみ意味があります。したがって、ゲームエンティティが削除された場合、debug / statsオブジェクトはこれを認識し、それ自体を削除する必要があります。(別のアイデアは追跡ミサイルです。それ自体を削除する代わりに、新しいターゲットを検索する場合があります。)

デバッグ/統計ロジックをゲームエンティティから分離したいと思います。ゲームエンティティは、debug/statsオブジェクトがアタッチされていることを知る必要はありません。弱い/保護されたポインターに対する答えを好む一方で、特定のタスクにアプローチするためのさまざまな方法も歓迎します。オブジェクトの存続期間を追跡し、メモリアドレスへの生のポインタの代わりにハンドルを使用するゲームオブジェクトマネージャを実装する必要があるかもしれないと考えています。

私はC++で開発しています。

4

2 に答える 2

17

lock()のメンバーを使用して、例外を処理せずboost::weak_ptrにの値をテスト(および使用)できるようにすることができます。weak_ptr

于 2009-12-09T19:19:47.770 に答える
10

これはゲーム開発ではよくあることです。通常、Boost ウィーク ポインターではなく、オブジェクト ハンドルのシステムが使用されます。これは、基礎となるルックアップ テーブルを定数メモリにする必要があり、Boost が取得していない追加情報または保証が必要になる場合があるためです。

通常のアプローチは、ポインターからポインターへの詳細化を使用することです。エンティティは、ポインターではなくハンドルによって参照されます。ハンドルは、エンティティへのポインターの大きな配列へのインデックスです。エンティティが停止すると、エンティティ テーブル内のポインタが NULL になります。

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 になるのではなく、まったく別のオブジェクトを指すハンドルを持つことになります。そのため、各エンティティにグローバルに一意の番号を付与し、それをハンドルにも格納します。

もちろん、std ベクトル、マップ、ディクショナリ、またはその他の種類のデータ構造をエンティティ テーブルに使用することもできますが、私たちの要件は通常、一定のメモリ、キャッシュの一貫性、および絶対的な最大パフォーマンス (handle_t::Get から) でした。 () はフレームごとに何千回も呼び出されます)。

于 2009-12-09T20:10:51.557 に答える