Я реализую фабричный шаблон для создания компонентов и хочу реализовать одноэлементный контейнер для всех экземпляров каждого типа, созданных фабрикой. В идеале это должен быть один вектор для каждого типа, созданного на фабрике.
Это было бы действительно легко, если бы я мог сохранить указатели базового класса в векторе, но, увы, мой сценарий использования предпочел бы, чтобы все экземпляры хранились непрерывно, а не там, где новые помещают их, чтобы получить как можно больше попаданий в кэш.
Я думал о том, чтобы сделать что-то вроде этого для фабричной карты:
Map<string,pair<constructorFnPtr, vector<baseClass>>
Это приводит к потере данных из производного класса при его приведении к базовому классу.
Я также думал, что указатель на вектор в качестве второго члена пары будет хорошим способом сделать это, но я не уверен, как это можно реализовать, сохраняя в каждом векторе свой тип данных. Я не думаю, что это было бы возможно, поскольку шаблонные векторы — это технически разные классы.
Есть ли способ сделать то, что я пытаюсь сделать? Последние пару дней я пытался что-то выяснить без удачи.
В качестве альтернативы, если есть другой хороший способ хранения векторов (то есть как статический член класса компонента), я открыт для любых предложений, подобных этому!
Я бы не рассматривал использование фабричного шаблона для компонентов, а скорее шаблон пула объектов, так как вы, вероятно, захотите использовать фабричный шаблон для управления созданием сущностей.
Я использую базу Component
класс для всех компонентов. Это позволяет мне иметь возможность управлять некоторой статической информацией о типах времени выполнения для каждого компонента и предоставлять набор общих методов. Затем я реализовал интерфейс IComponentPool
это контракт для моего пула объектов компонентов. Затем я определил шаблонный класс ComponentPool<T>
что происходит от IComponentPool
, Внутри этого шаблонного класса я управляю двумя векторами / массивами. Тогда есть ComponentPoolMap
который выставляет некоторое похожее на карту поведение на поиск ComponentPool<T>
на основе типов компонентов.
Сейчас в ComponentPool<T>
класс, первый массив является разреженным массивом, используемым как поиск. Он содержит смещение индекса относительно того, где компонент находится во втором плотно упакованном массиве. Разреженный массив может быть просто средством взять EntityId и преобразовать его туда, где находится компонент. Если хотите, вы можете легко внедрить более сложную систему управления верхом этого типа фреймворка.
Идея здесь заключается в том, что упакованный плотный объект выступает в качестве непрерывного буфера памяти, который вы можете легко перебирать в дружественном кэшу поместье в тесных циклах, но разреженный массив обеспечивает одноуровневый поиск косвенного обращения для каждой сущности для компонентов.
Теперь фабричный образец — то, где вы создаете свой Entity
или же EntityId
обращаться к сущности и создать все необходимое аспекты которые составляют орка, зомби или что-то еще для вашей игры. Фабрика действует как слой, который находится поверх вашей системы игровых объектов, из которой ваш ComponentPoolMap
вероятно, только небольшой кусочек этой системы.
Вы не можете сделать это с помощью std :: vector смежных объектов.
Причина в том, что фабрика должна строить объекты, а затем возвращать указатель на них. Проблема в том, что указатель будет храниться в вашем приложении во время следующего вызова your_vector.push_back()
скорее всего, сделает их недействительными, как говорится в документации C ++:
Если новый размер () больше емкости (), то все итераторы и
ссылки (в том числе итератор конца-в-конце) становятся недействительными.
В противном случае только последний итератор становится недействительным.
Таким образом, ваш следующий вызов на завод может сделать недействительными все ваши предыдущие вызовы.