1

这是一个设计问题,假设 C++ 和引用计数对象层次结构。我的代码库中的许多类都派生自一个公共基类 (ObjectBase),它实现了 retain() 和 release() 方法来增加和减少对象实例的引用计数。

可以使用许多用户可定义的内存分配器在堆栈或堆上创建对象的每个实例。如果retainCount 达到0,为了让对象实例在release() 方法中自杀(删除this),实例必须知道它是用哪个分配器构造的。

目前,我正在使用任意分配器为对象实例分配内存,然后调用placement new 来构造对象实例,并在对象上调用 setAllocator() 方法来设置创建它的分配器。如果对象已经在栈上构建,分配器被设置为 NULL 并且 release() 不会调用 delete。这个过程非常多余,并且可能容易出错(内存泄漏,如果我忘记调用 setAllocator 等......)理想情况下,我希望将其设为这样的一步过程:

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

但这使得支持任意数量的构造函数参数变得非常困难。

我只是在寻找有关如何解决此问题的想法。我真的很喜欢能够引用计数对象而不必依赖智能指针的想法,尤其是因为大多数类都派生自一个公共基础,无论如何。

谢谢你的帮助。

弗洛里安

4

1 回答 1

1

看看这篇文章:C++ 中的重载新功能。您可以重载new运算符 forObjectBase以便它将分配器作为参数并完成其余工作:

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 SomeClassderived from 来创建对象ObjectBase

Edit: One potential problem with this is that you cannot allocate objects on the stack any more, because there is no way to initialize the allocator to NULL without affecting the how the overloaded new works.

Update: There is one last (dirty) hack to get it working with both stack and dynamic allocation. You can make new set a global variable (a class static member would work as well) pointing to the current allocator and the constructor could consume this and reset it to NULL. At all other times, this global will already be NULL so an object constructed on the stack will get a NULL allocator.

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 回答