Я хочу реализовать Handletype, как в этом примере.
(Короче говоря: структура Handle
содержит index
-member для массива с элементами. Его другой член count
проверяет, обновлен ли index
, соответствующий countArray
. count
и countArray
с фиксированным размером типа /bitfield (u32: 20bits))
Чтобы не ограничиваться 20-битными значениями размера генерации/счетчика, мне пришло в голову следующее: почему бы не позволить переполнению unsigned char count/countArray
целенаправленно? Я также мог бы сделать то же самое с методом modulo ( counter = ++counter % 0xff )
, но это еще одна дополнительная операция. Тогда пусть граф растет до 0xff
а переполнение снова установит его на 0
при 0xff + 1
. Это законно?
Вот моя псевдо-реализация (C++):
struct Handle
{
unsigned short index;
unsigned char count;
};
struct myData
{
unsigned short curIndex;
int* dataArray;
unsigned char* countArray;
Handle create()
{
// check if index not already used
// create object at dataArray[handle.index]
Handle handle;
handle.index = curIndex;
handle.count = countArray[curIndex];
return handle;
}
void destroy( const Handle& handle )
{
// delete object at dataArray[handle.index]
countArray[handle.index]++; // <-- overflow here?
}
bool isValid( const Handle& handle ) const
{
return handle.count == countArray[handle.index];
}
};
EDIT # 1: Да, эти интегральные типы должны быть без знака (как индексы)
Пока вы не используете signed
типы, вы в безопасности.
Технически типы unsigned
не переполняются:
46) Это означает, что беззнаковая арифметика не переполняется, потому что результат, который не может быть представлен результирующим беззнаковым целым типом, уменьшается по модулю число, которое больше одного наибольшего значения, которое может быть представлено результирующим целым целым целым.
countArray
используется signed char
, результат также будет определен, поскольку в countArray[handle.index]++
есть скрытое целочисленное продвижение.