using namespace std;
Рассмотрим традиционный подход ООП к управлению объектами/объектами:
struct Entity { bool alive{true}; }
struct Manager {
vector<unique_ptr<Entity>> entities; // Non cache-friendly
void update() {
// erase-remove_if idiom: remove all !alive entities
entities.erase(remove_if(begin(entities), end(entities),
[](const unique_ptr<Entity>& e){ return !e->alive; }));
}
};
struct UserObject {
// Even if Manager::entities contents are re-ordered
// this reference is still valid (if the entity was not deleted)
Entity& entity;
};
Тем не менее, я хотел бы попробовать ориентированный на данные подход: не динамически выделять экземпляры Entity
, но хранить их в кэшируемой линейной памяти.
struct Manager {
vector<Entity> entities; // Cache-friendly
void update() { /* erase-remove_if !alive entities */ }
};
struct UserObject {
// This reference may unexpectedly become invalid
Entity& entity;
};
Кажется приятным. Но... если std::vector
необходимо перераспределить свой внутренний массив, все ссылки на объекты станут недействительными.
Решение использует класс дескриптора.
struct Entity { bool alive{true}; };
struct EntityHandle { int index; };
struct Manager {
vector<Entity> entities; // Cache-friendly
void update() { /* erase-remove_if !alive entities */ }
Entity& getEntity(EntityHandle h) { return entities[h.index]; }
};
struct UserObject { EntityHandle entity; };
Если я только добавляю/удаляю объекты на обратной стороне вектора, он работает. Я могу использовать метод getEntity
для получения объекта, который я хочу.
Но что, если я удалю Entity
из середины вектора? Все экземпляры EntityHandle
теперь будут содержать неправильный индекс, поскольку все было смещено. Пример:
Ручка указывает на индекс: 2
Объект A удаляется во время обновления()
Теперь дескриптор указывает на неправильный объект.
Как обычно эта проблема решается?
Обновлены ли индексы ручек?
Является ли мертвая сущность заменена заполнителем?
Чтобы уточнить:
Это и это являются примерами того, что Я имею в виду дизайн с поддержкой кэширования.
Кроме того, системы компонентов, такие как Artemis, утверждают, что они имеют линейный подход к кешированию, и используют решения, подобные ручкам. Как они справляются с проблемой, которую я описываю в этом вопросе?