Элегантное управление указателями на уничтоженные объекты в игровом движке - PullRequest
1 голос
/ 13 марта 2020

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

Вот проблема:

  1. Создание объекта A в движке
  2. Получить указатель на объект A - ObjectA *
  3. Уничтожить объект A
  4. ObjectA * становится висячим указателем

Использование shared_ptr - это не- go так как он может блокировать объекты, которые мы не хотим. В уничтожении объекта А нет ничего плохого, мне просто нужен способ проверить, есть ли у него.

У меня есть два решения этой проблемы:

Первое - просто возвращать суррогатный объект всякий раз, когда Вы хотите ссылку на объект. Этот суррогатный объект может иметь неявное преобразование в необработанный указатель, для случаев, когда мы точно знаем, что объект допустим. В тех случаях, когда мы храним ссылку дольше, мы будем использовать суррогатный объект, который в основном является просто указателем на указатель. Когда объект уничтожен, мы просто устанавливаем его указатель на nullptr, который суррогат сможет проверить на

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

Вот требования к моему предпочтительному элегантному решению:

  1. Используется только необработанные указатели для ссылок
  2. Указанные необработанные указатели возвращаются из вызовов функций (т.е. Ptr* AddCompoenent<>() вместо void AddComponent<>(Ptr*&)
  3. Указатели станут nullptr, когда объект, на который они указывают, уничтожен

Это вообще возможно?

1 Ответ

2 голосов
/ 13 марта 2020

Если вы хотите вернуть простые указатели, нет способа собрать все указатели на объект при его освобождении и установить их на nullptr, если вы просто используете обычные объекты C ++.

Существует Конечно, решение не новое и называется сборкой мусора. Это именно тот алгоритм, который вам нужен для этого; он анализирует стек и кучу и может собрать все указатели на ваш объект. Вместо того, чтобы сохранять объект, если он находит указатели на него, вы хотите, чтобы он установил указатели на nullptr.

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

Более того, последствия использования этого алгоритма для производительности ужасны: каждый раз, когда вы освобождаете объект, вам нужно будет проанализировать весь стек и кучу. Это означало бы, что он запускается гораздо чаще, чем обычный язык на основе g c, и смотрит на потери производительности из-за него.

...