简体   繁体   中英

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.

Calling ::delete on a pointer returned from a call to ::new is safe. Calling ::delete[] on a pointer returned from a call to ::new[] is safe. Calling delete x on a pointer returned from a call to auto x = new {...} is safe if you don't away x's type. Calling delete[] x on a pointer returned from a call to auto x = new {...}[z] is safe if you don't away x's type. mixing is UB

"but how does ::delete( ptr ) know the size of the data that ptr is pointing to"

The dynamic allocated memory in C++ is usually implemented through a heap. The heap initially allocates a very large amount of space, and than he handles it, letting the program handle random chunks from it. The heap stores the size of every chunk of memory it allocates. For example, if you need 8 bytes of memory, the heap reserve for you at least 12 bytes, holding the size in the first 4 bytes and the data in the 8 latter. Than, it returns a pointer to the 8 bytes. So, in the process of deleting, the program knows how much "to delete" through accessing the pointer - 4.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM