我正在创建 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 返回指向另一个已分配块的指针(不同的指针)已分配的对象已复制到新位置,并且存储在 components[typeIndex()] 内的所有 ptrs 变得无效(
我该如何解决?一种选择是返回一些 ComponentHandle 而不是 T*,如果内部内存块已移动,则使用新指针更新所有已返回的句柄,但这会降低分配速度并产生一些限制。
而且我知道 boost::pool_allocator,但是我的游戏太小而无法集成这样的库。