Я создаю pooled_allocator для выделения памяти для моих компонентов определенного типа в одном блоке памяти. Как я могу обновить уже выделенные ptrs, хранящиеся в каком-либо контейнере?
Я внедрил ECS для своей игры с общим подходом. Я использовал
std::unordered_map<TypeIndex, vector<BaseComponent*>>
для хранения моих компонентов по типу.
И вот как я сейчас распределяю память для компонентов.
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 });
}
Итак, теперь я хочу реализовать некоторый pooled_allocator, который должен удовлетворять всем требованиям std :: allocator_traits, чтобы использовать его в качестве распределителя для моих компонентов. Но я хочу сделать его динамичным, чтобы он мог расширить блок внутренней памяти.
Что у меня сейчас?
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)...);
}
}
Проблема в том, что realloc возвращает указатель на другой выделенный блок (другой указатель), уже выделенные объекты скопировали в новое место, и все ptrs, хранящиеся в компонентах [typeIndex ()], становятся недействительными (
Как я могу это исправить? Одним из вариантов является возврат некоторого ComponentHandle вместо T *, и если блок внутренней памяти переместился, обновите все уже возвращенные дескрипторы новыми указателями, но это уменьшит скорость выделения и наложит некоторые ограничения.
И я знаю о boost :: pool_allocator, но моя игра слишком мала, чтобы интегрировать такие библиотеки.