I have an OOP entity-component system that currently works like this:
// In the component system
struct Component { virtual void update() = 0; }
struct Entity
{
bool alive{true};
vector<unique_ptr<Component>> components;
void update() { for(const auto& c : components) c->update(); }
}
// In the user application
struct MyComp : Component
{
void update() override { ... }
}
To create new entities and components, I use C++'s usual new
and delete
:
// In the component system
struct Manager
{
vector<unique_ptr<Entity>> entities;
Entity& createEntity()
{
auto result(new Entity);
entities.emplace_back(result);
return *result;
}
template<typename TComp, typename... TArgs>
TComp& createComponent(Entity& mEntity, TArgs... mArgs)
{
auto result(new TComp(forward<TArgs>(mArgs)...));
mEntity.components.emplace_back(result);
return result;
}
void removeDead() { /* remove all entities with 'alive == false' - 'delete' is called here by the 'unique_ptr' */ }
}
// In the user application
{
Manager m;
auto& myEntity(m.createEntity());
auto& myComp(m.createComponent<MyComp>(myEntity));
// Do stuff with myEntity and myComp
m.removeDead();
}
The system works fine, and I like the syntax and flexibility. However, when continuously adding and removing entities and components to the manager, memory allocation/deallocation slows down the application. (I've profiled and determined that the slow down is caused by new
and delete
).
I've recently read that it's possible to pre-allocate heap memory in C++ - how can that be applied to my situation?
Desired result:
// In the user application
{
Manager m{1000};
// This manager can hold about 1000 entities with components
// (may not be 1000 because of dynamic component size,
// since the user can define it's on components, but it's ok for me)
auto& myEntity(m.createEntity());
auto& myComp(m.createComponent<MyComp>(myEntity));
// Do stuff with myEntity and myComp
m.removeDead();
// No 'delete' is called here! Memory of the 'dead' entities can
// be reused for new entity creation
}
// Manager goes out of scope: 'delete' is called here