2010-08-22 60 views
1

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

对象的每个实例都可以使用多个用户可定义的内存分配器在堆栈或堆上创建。如果retainCount达到0,为了让对象实例在release()方法中自杀(删除这个),实例必须知道它已经构建了哪个分配器。现在,我使用任意的分配器为对象实例分配内存,然后调用placement new来构造对象实例,并在对象上调用setAllocator()方法来设置它已经创建的分配器。如果对象已经在堆栈上构建,则分配器将设置为NULL,并且release()不会调用delete。这个过程是非常多余的,可能容易出错(内存泄漏,如果我忘了打电话setAllocator,等...),理想情况下我会想使之成为一个一个步骤的过程是这样的:

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

但是这使得它很难支持任意数量的构造函数参数。

我只是在寻找如何解决这个问题的想法。我非常喜欢能够引用计数对象而不必依靠智能指针的想法,特别是因为大多数类都来自公共基地,无论如何。

感谢您的帮助。

弗洛里安

回答

1

看一看这篇文章:Overloading New in C++。你可以重载new运营商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(...)其中SomeClassObjectBase派生的对象。

编辑:一个与这个潜在的问题是,你不能分配的堆栈中的任何更多的对象,因为没有办法分配器初始化NULL而不影响超载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; 
} 
+0

卡萨布兰卡,感谢您的快速响应,并感谢您在我的OT中修复源标签!我已经考虑了一个类似于你的建议的方法,但正如你正确指出的那样,我不能够在栈上创建对象了。我曾考虑检查ObjectBase构造函数,分配器字段是否指向有效的分配器实例,如果没有,则考虑将对象放在堆栈上。然而,考虑到未初始化的分配器字段恰好指向有效的分配器的一些(尽管很小)的机会,这是危险的业务。 – FlorianZ 2010-08-22 04:47:44

+0

@FlorianZ:查看我更新的答案,了解另一种可能的黑客行为。 – casablanca 2010-08-22 04:58:39

+0

@casablanca。这也是一个不错的主意!我唯一担心的是它可能不是线程安全的。如果在运算符new返回后发生上下文切换,但在构造函数有机会使用currentAllocator变量之前该怎么办?如果分配然后在第二个线程中执行,则currentAllocator将受到影响。关于如何使您的解决方案线程安全的任何想法? – FlorianZ 2010-08-22 05:28:04