В этом вопросе есть несколько частей, поэтому название немного расплывчато. Некоторые из синтаксиса оставлены для краткости. Большинство из них просто используют некоторые удобные примеры для обучения, что я имею в виду под этим, может стать очевидным.Написание/Проектирование простого менеджера объектов (игровой контекст)
Я начал что-то вроде этого:
class EntityManager {
// ...
private:
map<string, Entity> _entities;
}
// definition of some add method
void EntityManager::add (...) {
_entities.emplace(std::piecewise_construct,
std::forward_as_tuple(...),
/* and so on */);
}
где карта будет занимать весь игровой объект (который фиксируется в размере), и добавление будет включать emplace
.
Вопрос 1. Является ли это умным? Или это неэффективно каким-то образом против удерживания указателя как значения на карте?
Вопрос 2. Скажите, что Entity
(или какой-то подкласс) в какой-то мере стал динамическим. Есть ли что-нибудь, чтобы остановить этот подход от его обработки?
Я предполагаю, что emplace
выделит объект в куче и сохранит внутренний указатель. Я могу написать метод get
, подобный этому, чтобы рассматривать его как ссылку.
Entity& EntityManager::get(std::string entityId)
{
auto results = _gameEntities.find(entityId);
if (results == _gameEntities.end()) {
return Entity(); //this is bad, right?
}
return results->second;
}
Вопрос 3. Конечно, возвращающая ссылку на локальный стек распределённая объект плохо. Поскольку я не могу вернуть NULL, это единственное решение для использования исключений?
Единственная «проблема» с этим map<string, Entity>
подходом я заметил, что я могу только внести изменения в объект игры, который я создаю первым add
ИНГ его, затем запрашивает ссылку на него с get
, а затем внести изменения. Это немного уродливо, а также добавляет некоторые накладные расходы на создание объектов.
Так что теперь, я переключаюсь на конструкции указателя:
class EntityManager {
// ...
private:
map<string, unique_ptr<Entity>> _entities;
}
Это дает мне два варианта, как обрабатывать добавление элементов
// OPTION 1: create a unique_ptr elsewhere, then move it.
void EntityManager::add(string id, unique_ptr<Entity> ptr) {
_entities.insert(std::make_pair(id, std::move(ptr)));
}
// object creation
unique_ptr<Entity> uPtr(new Entity());
_entityManager.add("entity1", std::move(uPtr));
// OR
// OPTION 2: Create a naked pointer elsewhere, create a unique_ptr on insert
void EntityManager::add(string id, Entity* ptr) {
_entities.insert(make_pair(id, unique_ptr<Entity>(ptr)));
}
// object creation
Entity* e = new Entity();
_entityManager.add("entity1", e);
Вопрос 4. Есть ли эффективно разницу между эти подходы? Или предпочтительный способ?
Я думаю, что это все конкретные предметы, которые у меня есть, спасибо за чтение. На самом деле ...
Вопрос 5. Есть ли что-нибудь, что выпрыгивает как неправильное/заметное, что я пропустил?
** 5 вопросов ** в одном !! Это не совсем подходит для формата SO Q/A. Лучше спросить ** один ** главный вопрос, например, например._'Что я могу сделать, чтобы улучшить дизайн/реализацию класса EntityManager'_ и перечислить ваши сомнения в списке. –
А затем разместите его на codereview. –
Этот вопрос не соответствует теме, потому что он принадлежит [Stack Exchange Codereview] (http://codereview.stackexchange.com/). Извините, формат не подходит для SO! –