умные указатели — безопасное удаление объектов в C ++

Я пишу относительно большой проект на C ++ и имею проблему с удалением объекта. Проект, если быть точным, это игра в стиле roguelike.

У меня есть класс Npc который каждый монстр в игре. Они создаются и хранятся в отдельном классе, Storage<Npc>, который отвечает за их управление (загрузка, сохранение, создание, удаление и т. д.). Всякий раз, когда умирает монстр, соответствующий объект npc должен быть удален и уничтожен полностью. Удалить сам объект не проблема, я просто вызвал метод из Storage<NPC>, Проблема в том, что код содержит много указателей на этот уже мертвый npc, которые сейчас недействительны и попытка их использования вызовет много проблем. Например:

  1. Там может быть действие, которое он намеревался выполнить, прежде чем он умер.
  2. Плитка, на которой он стоял, хранит пластинку указателя на него.
  3. Он, возможно, был вовлечен в некоторые непрерывные действия, такие как схватка кого-то.

В коде много таких указателей, поэтому практически невозможно просто отследить их. Мне нужен какой-то способ определить, что npc уже мертв, и по этому адресу не хранится фактический объект, так что части кода, которые все еще имеют этот указатель, могут адекватно реагировать на его смерть.

Я сам выдвинул несколько идей, но пока ни одна из них не кажется мне действительно хорошей:

  • Я мог бы спросить Storage<NPC> класс, если у него есть объект по такому адресу. Потенциальная проблема заключается в том, что после удаления объекта другой объект может быть размещен по тому же адресу, что приведет к ошибкам.
  • Я мог бы уведомить все местоположения, которые могли бы использовать недопустимый указатель. Это плохая идея, потому что количество таких мест будет увеличиваться с течением времени, и делать это будет больно.
  • Я мог бы реализовать некоторую версию умного указателя, но я не уверен, какой из них использовать.

TL; Dr версияМне нужно решение, которое скажет мне, если указатель указывает на объект, или он указывает на свободный кусок памяти, или на некоторый другой объект, выделенный после удаления исходного объекта.

2

Решение

Как насчет использования слабых указателей? Если вы храните Npc в std::shared_ptr (C ++ 11, используйте std::tr1::shared_ptr для C ++ 03), вы можете создать std::weak_ptrs (снова C ++ 11, используйте std::tr1::weak_ptr для C ++ 03), которые относятся к shared_ptr, Когда shared_ptr на самом деле удаляет свой объект, то все weak_ptrS сможет понять это.

Хотя мне интересно, почему вы удаляете Npcs, которые все еще используются в другом месте (например, которые все еще имеют действия). Если вместо того, чтобы пытаться обнаружить все эти ссылки, вы удалили Npcты просто хочешь Npc умереть, как только все ссылки исчезнут, а затем с помощью shared_ptr сам по себе (без weak_ptr) будет работать правильно.

2

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

С предоставленной вами информацией я могу предложить вам Шаблон наблюдателя.
Если есть код, который должен реагировать на смерть неигрового персонажа, этот путь — путь. Разделы кода, имеющие ссылки на указатель на вашего NPC, будут уведомлены о смерти NPC и обнулит свою копию указателя на NPC, и при необходимости отреагируют на смерть NPC. Уведомление о смерти отправлено всем observers до того, как NPC фактически удален.

С помощью этого паттерна вы можете реализовать такую ​​механику, как «Герой получает 50 HP за каждого убитого монстра», и она легко масштабируется.

Вы также можете использовать предложение Кевина Балларда об использовании shared_ptr если никакой код не должен активно реагировать на смерть NPC, а просто должен обработать случай, когда NPC мертв.

3

Одним из вариантов является включение подсчета ссылок в ваш класс. Когда какой-либо другой объект (например, комната) будет содержать указатель на NPC, комната несет ответственность за увеличение количества ссылок NPC. Теперь, вместо того, чтобы просто удалить мертвый NPC, вы помечаете его как мертвый (через другой новый элемент данных, если у вас еще нет правильного флага), и удаляете только, если его счетчик ссылок равен нулю. Комнатный объект также обязан периодически проверять этот флаг, и если он узнает, что npc мертв, он уменьшает его счетчик ссылок (что приведет к удалению после вскрытия, если счет теперь равен нулю).

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