Является ли хорошей практикой использование вектора байтов в качестве исходного хранилища для других типов?

Я начал следовать учебному пособию по ECS на YouTube и никогда не видел, чтобы кто-то выделял новую переменную в vector из uint8 до.

template<typename Component>
uint32 ECSComponentCreate(Array<uint8>& memory, EntityHandle entity, BaseECSComponent* comp)
{
uint32 index = memory.size();
memory.resize(index+Component::SIZE);
Component* component = new(&memory[index])Component(*(Component*)comp);
component->entity = entity;
return index;
}

(полный код можно найти Вот; Array здесь #define Array std::vector)

Чем он отличается от использования вектора указателей, почему он лучше?

0

Решение

Это в основном «распределитель пула». Теперь, когда вы знаете, как это называется, вы можете прочитать о том, почему это делается, но производительность, как правило, является мотивацией.

Все распределения выполняются в одном векторе, и в конце весь вектор может быть освобожден сразу (после уничтожения объектов внутри, что вы можете увидеть в функции освобождения чуть ниже).

1

Другие решения

Две ошибки мне с помощью vector из байтов:

  1. Выравнивание. Хотя вы можете решить это с помощью распределенного распределителя. Если вы не знаете, какие типы хранятся заранее и каковы их требования к выравниванию до времени выполнения, то немного расточительно (но не так много для нескольких больших контейнеров) просто используйте максимальное выравнивание для динамического распределения.
  2. Это большая проблема в моей книге, и это связано с тем, как вектор перераспределяет свой массив при вставке в него элементов. Если вы храните нетривиально конструктивные / разрушаемые типы там, это может привести к хаосу, копируя их байты в память без надлежащего вызова необходимых движущих / копирующих ctors и dtors.

Если вы хотите, чтобы ваш ECS хранил новые типы компонентов непрерывно в памяти, то гораздо менее опасный подход, который я рекомендую, это абстрагировать контейнер компонентов, например:

struct Components
{
virtual ~Components() {}
};

template <class T>
struct ComponentsT: public Components
{
std::vector<T> components;
};

Когда вы хотите зарегистрировать новый тип компонента, Fooдля системы, вы можете динамически распределять и создавать ComponentsT<Foo>вставьте это в полиморфный контейнер (контейнер контейнеров), и когда вы хотите добавить Foo компонент к объекту (и, следовательно, создать его экземпляр и добавить его в список компонентов), получить соответствующий реферат Components* Базовый указатель / ссылка, уменьшить его (можно использовать dynamic_cast) чтобы ComponentsT<Foo>*, затем отодвиньте туда свой компонентный экземпляр Теперь вы получили все свои Foos хранится непрерывно в памяти, не имея дело с выравниванием и аннулированием и так далее.

0

По вопросам рекламы [email protected]