2010-08-22 32 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