简体   繁体   中英

Storing and recycling heap-allocated variable size objects without malloc and free

I want to store polymorphic objects with variable size that derive from the Base class on the free store.

I also want to store a bool value in the same memory block, right before the memory reserved for the derived object.

/* 
    Desired memory layout for storage of one object:

    base address
    v
    |      |                                   |     
    | bool | . . . . . variable size . . . . . |               
    |      |                                   |
           ^                                   ^
           object address                      end address
*/

The first thing I tried was creating a struct with a bool member and an aligned storage of a template-passed parameter std::size_t size.

I've tried using offsetof and reinterpret_cast like in one of my previous questions , but the program always crashed and I wasn't able to debug the error.

Therefore, I tried using std::malloc and std::free , and the program works as expected. However I'm now lacking C++ new / delete safety and I don't have any kind of alignment.

I would really like to find a way to re-implement the code below using std::aligned_storage or something that assures me the code will work on any platform and will be standard-compliant.

I want to store the additional bool in memory before the actual object.

struct Base { virtual ~Base() { } };
struct Der1 : Base { char c[100]; };
struct Der2 : Base { char c[200]; };

template<typename TBase> struct LocalRecycler
{
    // Allocated, but unused pointers, that can be recycled
    std::vector<void*> recyclable;

    // Upon destruction, free all allocated memory
    // No need to call the destructors, as I'm 100% sure recyclable 
    // pointers alredy destroyed their inner object
    ~LocalRecycler() 
    { 
        for(auto p : recyclable) free(p); 
    }

    // I'm omitting variadic template parameters for generic construction,
    // as they are not relevant to the question
    template<typename T> T* create() 
    {
         void* objAddress;

         // If we have some space that is already allocated, use it
         // Otherwise, allocate new space
         if(!recyclable.empty())
         {
             objAddress = recyclable.back();
             recyclable.pop_back();
         }
         else 
         { 
             // Note how I'm not taking into account alignment here
             // That's one reason why I would like to avoid using `std::malloc`
             objAddress = std::malloc(sizeof(bool) + sizeof(T));
         }

         // Construct a `bool` at the beginning of the allocated memory block
         // Construct a `T' after the bool
         new (objAddress + 0)            bool{true};
         new (objAddress + sizeof(bool)) T{};

         return reinterpret_cast<T*>(objAddress + sizeof(bool));
    }

    void recycle(void* mPtr)
    {
        // Destroy the inner object
        TBase* basePtr{reinterpret_cast<TBase*>(mPtr + sizeof(bool))};
        basePtr->TBase::~TBase();

        // The memory block can now be reused
        recyclable.emplace_back(mPtr);
    }
};

The above code seems to work properly in my program.

What I am asking is: how can I "convert" the above C-style code to modern C++11/C++14 code, also taking care of alignment?

It seems that creating a class like the following do the job:

template <typename T>
struct ClassWithBool
{
    bool b;
    T t;
};

And then you may use std::allocator to allocate/destroy the object.

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