jeudi 22 septembre 2016

Does ::operator delete( void * ) know the size of memory allocated with ::operator new( size_t )

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.

Aucun commentaire:

Enregistrer un commentaire