This is a design question, assuming C++ and a reference counted object hierarchy. A lot of classes in my codebase derive from a common base class (ObjectBase), which implements retain() and release() methods to increase and decrease the reference count of an object instance.
Every instance of an object may be created on the stack or on the heap, using a number of user definable memory allocators. In order for the object instance to commit suicide (delete this) in the release() method if the retainCount reaches 0, the instance must know which allocator it has been constructed with.
At the moment, I am allocating memory for an object instance using an arbitrary allocator, then call placement new to construct the object instance and call a setAllocator() method on the object to set the allocator it has been created with. If the object has been constructed on the stack, the allocator is set to NULL and release() will not call delete. This process is very redundant and potentially error prone (memory leaks, if I forget to call setAllocator, etc…) Ideally I would want to make this a one-step process like this:
Object* o = myPoolAllocator.allocate<Object>(constructor arguments... );
But this makes it very difficult to support and arbitrary number of constructor arguments.
I am just looking for ideas on how to solve this problem. I really like the idea of being able to reference count objects without having to rely on a smart pointer, especially since most classes derive from a common base, anyways.
Thanks for your help.
Florian
Have a look at this article: Overloading New in C++ . You could overload the
newoperator forObjectBaseso that it takes your allocator as a parameter and does the rest of the job:Normally, the operator is supposed to just return a pointer to the allocated memory, but since you need access to the new object to call your
setAllocatormethod, I’ve included a hack that should (but may not) work. Note that the actualObjectBaseconstructor is called after the above function returns, so you should make sure that your constructor does not re-initialize the allocator member.And then a similar overload for
delete:You would then create objects by calling
new (allocator) SomeClass(...)whereSomeClassderives fromObjectBase.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
NULLwithout affecting the how the overloadednewworks.Update: There is one last (dirty) hack to get it working with both stack and dynamic allocation. You can make
newset 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 toNULL. At all other times, this global will already beNULLso an object constructed on the stack will get aNULLallocator.