Search code examples
c++templatesmemory-managementtypesallocator

Determine the type of a pointer


So I am making a Memory Stack Allocator that is capable of allocating any instance of any type onto the heap in a continuous fashion.

In order to do this i have added a 'AllocationHeader' class directly before each allocation which contains a void* to the instance address itself and a AllocationHeader* to the previous header. So far this has worked perfectly and i'm able to allocate and deallocate etc.

But i've ran into 1 (possibly 2) problems. In order to deallocate properly I also need to call the destructor of the object in question and then remove it from the stack. This is fine when i'm removing an instance that i have a pointer to as i can just pass it to the deallocate function and it knows what type it is and does its thing.

The problem lies when I want to create functions like deallocateAll() or deallocateAllAboveObject(T* obj) as I would need to know the types of each allocation without explicitly passing their pointer, so i could go down each allocation in the stack calling the deconstructor on each as I go.

What I would like is to be able to create an AllocationHeader which can store a pointer of any type, and then the type of the pointer can be retrieved at a later date without already knowing the type.

I'm really not sure how to do this as all suggestions that i've seen so far involve comparing the object with a specific type and seeing if they're the same. However I can't just check against each possible class in the program as there could be 1000's as I continue to build on this.

Alternatively if you have any suggestions for an alternative approach to a stack allocator that can deal with any type, that would be great as well.

Any help at all would be greatly appreciated.


Solution

  • Due to C++'s static type system, I can only see a couple of solutions to the problem

    • Make every type you use with the allocator derive from a (consistent) type with a virtual distructor e.g. struct destructible { virtual ~destructible() { } }, however this will potentially enlarge & alter the layout of any types you alter to derive from this.

    Or uppon allocation store a function object that does the destruction, e.g. using the following template

    template<typename T> void destroy(void* p) { reinterpret_cast<T*>(p)->T::~T(); }
    
    struct AllocationHeader
    {
        template<typename T> AllocationHeader(AllocationHeader* previouse, void* data)
            : previouse(previouse), data(data), destructor(&destroy<T>) { }
        AllocationHeader* previouse;
        void* data;
        void (*destructor)(void*);
    }
    void deallocateAll(AllocationHeader& start)
    {
        for (AllocationHeader* a = &start; a != nullptr; a = start->previouse;)
        {
            a->destructor(a->data);
            delete a->data;
        }
    }
    

    (Without providing your code for the AllocationHeader type it is difficuilt to help you.)

    Note: My compiler/IDE is currently reinstalling so I am unable to test the above code, I am pretty sure about most of it, except I may need to put a typename in the destructor call syntax reinterpret_cast<T*>(p).T::~T();

    EDIT Using a template constructor, where the template arguments cannot be inferred is a bad idea, the following constructor should be used instead

    AllocationHeader(AllocationHeader* previouse, void* data, void(*destructor)(void*))
            : previouse(previouse), data(data), destructor(destructor) { }
    

    Just pass &destroy<T> as the 3rd argument to it.