Простой, эффективный слабый указатель, который устанавливается равным нулю при освобождении целевой памяти
Существует ли простой, эффективный слабый / защищенный указатель? мне нужно несколько указателей на один и тот же объект, которые все автоматически устанавливаются в NULL, когда объект удаляется. Существует один" главный " указатель, который всегда используется для удаления объекта, но может быть несколько других указателей, ссылающихся на тот же объект.
Вот некоторые решения, которые не совсем соответствуют моим потребностям:
- QPointer : я не разрабатываю приложение QT; я не хочу включать это libary / производное от QObject.
-
boost:: weak_ptr:
исключение возникает при обращении к освобожденному объекту. Слишком дорого для моей ситуации: это должно быть нормально, чтобы проверить слабый указатель; я планирую сделать некоторую ручную очистку, когда слабый указатель больше не действителен.update : weak_ptr можно протестировать без исключения - слабые указатели с низкими накладными расходами : это очень близко к тому, что я ищу, за исключением того, что мне не нравится тот факт, что " это схема гарантированно работает только до тех пор, пока вы не Выделите 2**sizeof(int) раз в одном и том же месте."
Почему мне нужны эти слабые / защищенные указатели: У меня есть игра со списком игровых объектов. Некоторые объекты зависят от других, например объект отладки/статистики, связанный с игровой сущностью. Объект debug / status отображает полезную информацию о сущности игры, но она имеет смысл только в том случае, если сущность игры существует. Так что если игровой объект удален, то объект debug / stats должен осознать это и удалить себя. (Другая идея-это ракета слежения: вместо того, чтобы удалиться, она может искать новую цель.)
Я хочу, чтобы логика отладки/статистики была отделена от сущности игры. Игровой объект не должен знать, что к нему присоединен объект отладки/статистики. Хотя я бы предпочел ответ для слабых / защищенных указателей, я также приветствую различные способы подхода к моей конкретной задаче. Я думаю, что мне, возможно, придется реализовать игровой объект диспетчер , который отслеживает время жизни объекта и использует дескрипторы вместо необработанных указателей на адреса памяти.
Я развиваюсь в C++.
2 ответа:
Вы можете использовать
lock()
членboost::weak_ptr
, чтобы иметь возможность проверить (а затем использовать) значениеweak_ptr
, не имея дело с исключениями.
Это обычная вещь в разработке игр. Обычно используется система дескрипторов объектов, а не слабые указатели Boost, потому что нам нужно, чтобы базовая таблица поиска была постоянной памятью, а также потому, что иногда нам нужна дополнительная информация или гарантии, которые Boost не получил.
Обычный подход заключается в использовании детализации указателей на указатели. На объект ссылается дескриптор, а не указатель. Дескриптор-это индекс в большом массиве указателей на сущности. Когда сущность умирает, она обнуляет указатель в своей таблице сущностей.
Серийный номер необходим, потому что массив имеет постоянный размер - в конечном счете, вам нужно будет повторно использовать записи таблицы сущностей, и есть вероятность, что вы можете хранить дескриптор, скажем, индекса #743, достаточно долго, чтобы объект был удален, а ячейка #743 повторно использована для чего-то другого. Если бы у вас был просто указатель на список указателей, вы бы в конечном итоге получили дескриптор, который указывает на совершенно другой объект вместо того, чтобы стать нулем. Таким образом, мы даем каждой сущности глобально уникальный номер и храним его в дескрипторе. Конечно, для таблицы сущностей можно использовать вектор std, или карту, или словарь, или какую-то другую структуру данных, но наши требования обычно сводятся к постоянной памяти, когерентности кэша и абсолютной максимальной производительности (так как handle_t::Get() вызывается тысячи раз за кадр).struct handle_t { uint32 serialnumber; // this is a GUID for each entity; it increases // monotonically over the life of the process uint entityindex; inline Entity *Get(); } struct entityinfo_t { Entity *pEntity; // an entity's destructor NULLs this out on deletion uint32 serialnumber; } entityinfo_t g_EntityTable[MAX_ENTITIES]; Entity *handle_t::Get() { entityinfo_t &info = g_EntityTable[entityIndex]; if ( serialnumber == info.serialnumber ) { return info.pEntity; } else { return NULL; } }