1

これは、C++ と参照カウント オブジェクト階層を想定した設計上の問題です。私のコードベースの多くのクラスは、共通の基本クラス (ObjectBase) から派生しています。これは、retain() および release() メソッドを実装して、オブジェクト インスタンスの参照カウントを増減します。

オブジェクトのすべてのインスタンスは、多数のユーザー定義可能なメモリ アロケータを使用して、スタックまたはヒープ上に作成できます。オブジェクト インスタンスが release() メソッドで、retainCount が 0 に達したときに自殺する (これを削除する) ためには、インスタンスは、それがどのアロケーターで構築されたかを認識している必要があります。

現時点では、任意のアロケーターを使用してオブジェクト インスタンスにメモリを割り当てています。次に、placement new を呼び出してオブジェクト インスタンスを構築し、オブジェクトで setAllocator() メソッドを呼び出して、作成されたアロケーターを設定しています。オブジェクトがスタック上に構築されている場合、アロケータは NULL に設定され、release() は delete を呼び出しません。このプロセスは非常に冗長で、エラーが発生しやすい可能性があります (メモリ リーク、setAllocator の呼び出しを忘れた場合など)。

Object* o = myPoolAllocator.allocate<Object>(constructor arguments... );

ただし、これにより、任意の数のコンストラクター引数をサポートすることが非常に困難になります。

この問題を解決する方法についてのアイデアを探しています。特にほとんどのクラスは共通のベースから派生するため、スマート ポインターに依存せずにカウント オブジェクトを参照できるというアイデアが本当に気に入っています。

ご協力いただきありがとうございます。

フロリアン

4

1 に答える 1

1

この記事をご覧ください: Overloading New in C++newfor 演算子をオーバーロードしてObjectBase、アロケータをパラメーターとして受け取り、残りの作業を行うことができます。

void *ObjectBase::operator new(size_t size, Allocator *allocator) {
  void *ptr = allocator->allocate(size);

  // Hack to pre-initialize member before constructor is called
  ObjectBase *obj = static_cast<ObjectBase *>(ptr);
  obj->setAllocator(allocator);

  return ptr;
}

通常、オペレーターは割り当てられたメモリへのポインターを返すだけですが、setAllocatorメソッドを呼び出すには新しいオブジェクトにアクセスする必要があるため、動作するはずの (動作しない可能性がある) ハックを含めました。実際のObjectBaseコンストラクターは上記の関数が返された後に呼び出されることに注意してください。そのため、コンストラクターがアロケーター メンバーを再初期化しないようにする必要があります。

そして、同様の のオーバーロードdelete:

void ObjectBase::operator delete(void *ptr) {
  ObjectBase *obj = static_cast<ObjectBase *>(ptr);
  obj->getAllocator()->free(ptr);
}

new (allocator) SomeClass(...)次に、 where SomeClassextends fromを呼び出してオブジェクトを作成しますObjectBase

編集:NULLこれに関する潜在的な問題の1つは、オーバーロードされた動作に影響を与えずにアロケーターを初期化する方法がないため、スタックにオブジェクトを割り当てることができなくなることですnew

更新:スタックと動的割り当ての両方で動作させるための最後の (汚い) ハックがあります。new現在のアロケーターを指すグローバル変数 (クラスの静的メンバーも同様に機能します) を設定すると、コンストラクターはこれを消費して にリセットできますNULL。それ以外の場合は常に、このグローバルは既に存在NULLするため、スタック上に構築されたオブジェクトはNULLアロケーターを取得します。

Allocator *currentAllocator = NULL;

void *ObjectBase::operator new(size_t size, Allocator *allocator) {
  currentAllocator = allocator;
  return allocator->allocate(size);
}

ObjectBase::ObjectBase() {
  setAllocator(currentAllocator);
  currentAllocator = NULL;
}
于 2010-08-22T04:30:42.440 に答える