Context:
I am trying to create a custom allocator which mimics std::allocator
(not derived from) in some ways, but allows instanced allocators. My generic containers have constructors, which allow the user to specify a pointer, to a custom Allocator
object. When no allocator is specified, I want it to default to a singleton NewDeleteAllocator
which derives from a abstract Allocator
class. This simply wraps the global new
and delete
operators. This idea is taken from Towards a Better Allocator Model by Pablo Halpern.
Client code that uses custom allocator:
// 'foo_container.hpp'
// enclosed in package namespace
template <class T>
class FooContainer
{
private:
// -- Private member properties --
Allocator * allocator;
public:
// -- Constructors --
FooContainer( Allocator * allocator = 0 )
{
this->allocator = !allocator ? (Allocator *)defaultAllocator : allocator;
}
FooContainer( const FooContainer &rhs, Allocator * allocator = 0 )
{
// don't implicitly copy allocator
this->allocator = !allocator ? (Allocator *)defaultAllocator : allocator;
// copying logic goes here
}
}
Custom allocator implementation:
// 'allocator.hpp'
// enclosed in package namespace
class Allocator
{
public:
virtual ~Allocator(){ };
virtual void * allocate( size_t bytes ) = 0;
virtual void deallocate( void * ptr ) = 0;
};
class NewDeleteAllocator : public Allocator
{
public:
virtual ~NewDeleteAllocator()
{
}
virtual void * allocate( size_t bytes )
{
return ::operator new( bytes );
}
virtual void deallocate( void * ptr )
{
::operator delete( ptr ); // memory leak?
}
private:
};
//! @todo Only for testing purposes
const Allocator * defaultAllocator = new NewDeleteAllocator();
Main Question:
I know that allocating via new
might also store information about the allocation along with the pointer. I realize calling delete
with the scope resolution operator ::
is not quite the same as just calling delete
, but how does ::delete( ptr )
know the size of the data that ptr
is pointing to? Is this a safe operation? From my understanding, deleting via a void pointer could result in undefined behaviour, according to the C++ standard. If this is bad, how else could I implement this?
Further details:
I did some very rough preliminary testing with the following code:
// inside member function of 'FooContainer'
for( size_t i = 0; i < 1000000; i++ )
{
for( size_t j; j = 1; j < 20; j++ )
{
void * ptr = allocator->allocate( j );
allocator->deallocate( ptr );
}
}
I observed the program total memory usage with Xcode's profiling tools. Memory usage stays constant at a low value. I'm aware that this is not the proper way to check for memory leaks. I don't know if the compiler could optimize this out. I am just experimenting with the idea. I would really appreciate some input to the main question, before I make any commitments to the architecture of my library. The whole approach might be flawed in the first place.
Thanks for the input. I don't want to make any bad assumptions.