Bog'liq C -Eldjer-Djeff-for-Real-Programmers-RUS-www.itlibitum.ru
225 Type* operator->() { return (Type*)address; }
};
Шаблон дескриптора
Это уже знакомый нам шаблон дескриптора с подсчетом ссылок из предыдущей главы.
template class Handle {
private:
MP*
pointer;
public:
Handle() : pointer(new MP) { pointer->Grab(); }
Handle(const Handle& h) : pointer(h.pointer)
{ pointer->Grab(); }
Handle& operator=(const Handle& h)
{
if (this == &h) return *this;
if (pointer == h.pointer) return *this;
pointer->Release();
h.pointer->Grab();
return
*this;
}
MP& operator->() { return *pointer; }
};
В программе он используется для переменных, ссылающихся на объекты.
class Bar {
private:
H foo;
public:
void
f();
};
void Bar::f()
{
Handle f;
//
Эквивалентно Foo* f = new Foo;
f = foo;
// Использует operator=(Handle(foo));
foo
=
f;
//
Использует оператор H(f)
}
Пул ведущих указателей
Простоты ради мы предположим, что классы, производные от
VoidPtr
, совпадают по размеру с самим
VoidPtr
; иначе говоря, в них не добавляются новые переменные. Наша задача упрощается;
VoidPtrPool
теперь может быть простым связанным списком массивов
VoidPtr
. Структура массива
называется
VoidPtrBlock
.
struct VoidPtrBlock {
VoidPtrBlock*
next; //
Следующий блок в списке
VoidPtr
slots[BLOCKSIZE];
//
Массив позиций
VoidPtrBlock(VoidPtrBlock* next_in_list) : next(next_in_list)
{
//
Организовать новые позиции в связанный список
for (int i = 0; i < BLOCKSIZE - 1; i++)
226 slots[i].address = &slots[i + 1];
slots[BLOCKSIZE - 1].address = NULL;
}
~VoidPtrBlock() { delete next; }
}
class VoidPtrPool {
private:
VoidPtr*
free_list; //
Список свободных VoidPtr
VoidPtrBlock*
block_size;
//
Начало списка блоков
public:
VoidPtrPool() : block_list(NULL), free_list(NULL) {}
~VoidPtrPool() { delete block_list; }
VoidPtr*
Allocate();
void Deallocate(VoidPtr* vp);
};
VoidPtr* VoidPtrPool::Allocate()
{
if (free_list == NULL) // Выделить дополнительный блок
{
block_list = new VoidPtrBlock(block_list);
//
Добавить в список
block_list->slots[BLOCKSIZE – 1].address = free_list;
free_list = &block_list->slots[0];
}
VoidPtr* space = (VoidPtr*)free_list;
free_list = (VoidPtr*)space->address;
return
space;
}
void VoidPtrPool::Deallocate(VoidPtr* p)
{
vp->address = free_list;
free_list = (VoidPtr*)vp->address;
vp->size
=
0;
}
В общем, ничего хитрого. При выделении нового блока мы организуем его позиции связанный список
и водружаем поверх списка свободных указателей. Если список свободных указателей пуст, а нам
потребовался еще один ведущий указатель, мы выделяем новый блок, а затем берем указатель из
списка свободных, в котором к этому времени появились вакансии.
Итератор ведущих указателей
Для перебора всех ведущих указателей мы создадим класс итератора с именем
VoidPtrIterator
.
VoidPtrPool
возвращает итератор, перебирающий все активные указатели (то есть все указатели, не
присутствующие в списке свободных). Он будет объявлен как чисто абстрактный базовый класс,
поскольку в следующей главе тот же интерфейс будет использован для перебора указателей,
внедренных в объекты.
class VoidPtrIterator {
protected:
VoidPtrIterator()
{}
public:
virtual bool More() = 0;