Простой, эффективный слабый указатель, который устанавливается в NULL, когда целевая память освобождается

Если Ваши тесты не очень полны, Вы могли бы попасть в ложное чувство "всего, работает" просто, потому что Вы тестируете передачу. Теоретически, если Ваши тесты передают, код работает; но если бы мы могли бы записать коду отлично первый раз, когда нам не были бы нужны тесты. Мораль здесь должна удостовериться, что сделала проверку работоспособности самостоятельно прежде, чем назвать что-то завершенным, только полагайтесь на тесты.

На той ноте, если Ваша проверка работоспособности находит что-то, что не тестируется, удостоверьтесь, что возвратились и записали тест для него.

8
задан Palec 3 August 2017 в 16:22
поделиться

2 ответа

Вы можете использовать член lock () из boost :: weak_ptr , чтобы быть возможность протестировать (затем использовать) значение weak_ptr без обработки исключений.

16
ответ дан 5 December 2019 в 06:23
поделиться

Это обычная вещь в разработке игр. Обычно используется система дескрипторов объектов, а не слабые указатели Boost, потому что нам нужна базовая таблица поиска, чтобы быть постоянной памятью, и потому что иногда нам нужна дополнительная информация или гарантии, которых Boost не получил.

Обычный подход - использовать уточнение указателей на указатели. На объект ссылаются по дескриптору, а не по указателю. Дескриптор - это индекс в большом массиве указателей на сущности. Когда объект умирает, он обнуляет указатель в своей таблице объектов.

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;
  }
}

Серийный номер необходим, потому что массив имеет постоянный размер - в конечном итоге вам нужно будет повторно использовать записи таблицы объектов, и есть вероятность, что вы можете сохранить дескриптор, скажем, индекса # 743, достаточно долго, чтобы объект был удален, а ячейка № 743 повторно использовалась для чего-то еще. Если бы у вас был просто указатель на список указателей, вы бы получили дескриптор, указывающий на совершенно другой объект, а не на NULL. Итак, мы даем каждой сущности глобально уникальный номер и также сохраняем его в дескрипторе.

Конечно, вы можете использовать вектор std, карту, словарь или какую-либо другую структуру данных для таблицы сущностей, но наши требования обычно заключаются в постоянной памяти, согласованности кеша и абсолютной максимальной производительности (поскольку handle_t :: Get () вызывается тысячи раз за кадр).

мы даем каждой сущности глобальный уникальный номер и также сохраняем его в дескрипторе.

Конечно, вы можете использовать вектор std, карту, словарь или какую-либо другую структуру данных для таблицы сущностей, но наши требования обычно заключаются в постоянной памяти, согласованности кеша и абсолютной максимальной производительности (поскольку handle_t :: Get () вызывается тысячи раз за кадр).

мы даем каждой сущности глобальный уникальный номер и также сохраняем его в дескрипторе.

Конечно, вы можете использовать вектор std, карту, словарь или какую-либо другую структуру данных для таблицы сущностей, но наши требования обычно заключаются в постоянной памяти, согласованности кеша и абсолютной максимальной производительности (поскольку handle_t :: Get () вызывается тысячи раз за кадр).

10
ответ дан 5 December 2019 в 06:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: