简体   繁体   中英

Custom pooled memory allocator with realloc

I'm creating pooled_allocator to alloc memory for my components of specific type in one memory block. How can I update already allocated ptrs stored in some container?

I implemented ECS for my game with common approach. I used

std::unordered_map<TypeIndex, vector<BaseComponent*>>

to store my components by type.

And it is how I allocates memory for components now.

template<typename T, typename... Args>
T* Entity::assign(Args&&... args)
{
    //....
    // if there are no components of this type yet
    std::allocator<T> alloc;
    T* comp = std::allocator_traits<std::allocator<T>>::allocate(alloc, 1);

    std::allocator_traits<std::allocator<T>>::construct(alloc, comp, T(args...));

    // get container for type and add pointer to newly allocated component, that has to be stored in pool
    container.push_back(comp);
    components.insert({ getTypeIndex<T>(), container });
}

So, now I wanna implement some pooled_allocator, that should meet all std::allocator_traits requirenments to use it as allocator for my components. But I wanna to make it dynamic so it should be able to extend its internal memory block.

What I have for now?

template<typename T, unsigned int Size = 10>
class pooled_allocator
{
    // some typedefs
    typedef value_type * pointer;

    static void* m_memoryBlock; // malloc(SIZE*Size) or nullptr to reproduce problem
    static std::list<MyBlockNode> m_allocated;
    static const size_t SIZE; // sizeof(T)

    // some methods

    static pointer allocate(const size_t amount)
    {
        if (!m_memoryBlock)
            m_memoryBlock = malloc(amount * SIZE);
        else
        {
            // here realloc can return another pointer
            m_memoryBlock = realloc(m_memoryBlock, m_allocated.size() * SIZE + amount * SIZE);         
        }

        int index = m_allocated.size();
        m_allocated.push_back(MyBlockNode { });

        pointer elPointer = (pointer)((pointer)m_memoryBlock + index * SIZE);

        return elPointer;
    }

    template <class Up, class... Args>
    void construct(Up* p, Args&&... args)
    {
       new((void*)p) Up(std::forward<Args>(args)...);
    }
}

The problem is where realloc returns the pointer to another allocated block ( different pointer ) already allocated objects have copied to a new place and all ptrs stored inside components[typeIndex()] becomes invalid(

How I can fix it? One of the options is to return some ComponentHandle instead of T* and if internal memory block has moved, update all already returned handles with new pointers, but it will decrease allocation speed and makes some restrictions.

And I know about boost::pool_allocator, but my game is too small to integrate such libs.

You created your problem defining your own memory allocation like that.

A solution is to not realloc but to allocate a new block when needed, and to manage all these blocks.

But the real question is why do you do that ? You probably choose that way so solve an other problem, which one ?

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