Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 [ 71 ] 72 73 74 75 76 77 78 79 80 81 82

s1ots[i].address = &s1ots[i + 1]; s1ots[BLOCKSIZE - 1].address = NULL;

~VoidPtrBlock() { delete next; }

class VoidPtrPool { private:

VoidPtr* free 1ist; Список свободных VoidPtr VoidPtrBlock* b1ock size; Начало списка блоков

public:

VoidPtrPoo1() : b1ock 1ist(NULL), free 1ist(NULL) {}

~VoidPtrPoo1() { delete b1ock 1ist; }

VoidPtr* Al1ocate();

void Dea11ocate(VoidPtr* vp);

VoidPtr* VoidPtrPool::Al1ocate()

if (free 1ist == NULL) Выделить дополнительный блок

b1ock 1ist = new VoidPtrBlock(b1ock 1ist); Добавить в список

b1ock 1ist->s1ots[BLOCKSIZE - 1].address = free 1ist; free 1ist = &b1ock 1ist->s1ots[0];

VoidPtr* space = (VoidPtr*)free 1ist; free 1ist = (VoidPtr*)space->address; return space;

void VoidPtrPoo1::Dea11ocate(VoidPtr* p)

vp->address = free 1ist; free 1ist = (VoidPtr*)vp->address; vp->size = 0;

В общем, ничего хитрого. При выделении нового блока мы организуем его позиции связанный список и водружаем поверх списка свободных указателей. Если список свободных указателей пуст, а нам потребовался еще один ведущий указатель, мы выделяем новый блок, а затем берем указатель из списка свободных, в котором к этому времени появились вакансии.

Итератор ведущих указателей

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

class VoidPtrlterator { protected:

VoidPtrIterator() {}

public:

virtual bool More() = 0;



virtual VoidPtr* Next() = 0;

Сам итератор работает весьма прямолинейно. Он просто перебирает блоки в цикле и ищет указатели с ненулевым значением переменной size.

class VoidPtrPoollterator : public VoidPtrlterator { private:

VoidPtrBlock* block;

int slot; Номер позиции в текущем блоке

virtual void Advance() Найти следующую используемую позицию

while (block != NULL) {

if (slot >= BLOCKSIZE)

block = b1ock->next; slot = 0;

else if (b1ock->s1ots[s1ot].size != 0)

break; s1ot++;

public:

VoidPtrPoolIterator(VoidPtrBlock* vpb)

: block(vpb), s1ot(0), { Advance(); } virtual bool More() { return block != NULL; } virtual VoidPtr* Next()

VoidPtr* vp = &b1ock->s1ots[s1ot];

Advance();

return vp;

Кроме того, мы добавим в VoidPtrPool следующую функцию: VoidPtrIterator* iterator()

{ return new VoidPtrPoolIterator(this); }

Наконец, нам пришлось объявить VoidPtrPoolIterator другом VoidPtr, чтобы в программе можно было обратиться к его переменной size. Забегая вперед, скажу, что в главе 16 мы воспользуемся этим итератором для других целей; поэтому функция Advance() и объявлена виртуальной, чтобы производные классы могли добавить свою собственную фильтрацию. Если найденная позиция имеет нулевое значение size, мы пропускаем ее. Во всем остальном работа сводится к простому перебору в массивах, образующих блоки указателей.

Вариации

Перед тем как описывать сами алгоритмы уплотнения, давайте рассмотрим другие варианты исходной постановки задачи. Они не оказывают принципиального влияния на архитектуру или алгоритмы, а только на идиомы С++ в их реализации.



Невидимые ведущие указатели

Чтобы не использовать шаблоны дескрипторов и ведущих указателей, можно было организовать множественное наследование ведущих указателей от VoidPtr и гомоморфного базового класса. Иначе говоря, ведущие указатели становятся невидимыми, как объяснялось в предыдущих главах. В игру вступают все механизмы, сопутствующие идиоме невидимых указателей (например, производящие функции).

class Foo { public:

static Foo* make(); Возвращает пару указатель-указываемый объект

virtual void Member1() = 0;

И т.д. для открытого интерфейса

В файле foo.cpp

class FooPtr : public Foo, public VoidPtr { public:

FooPtr(Foo* foo, size t size) : VoidPtr(foo, size) {} virtual ~FooPtr() { delete (Foo*)address; } virtual void Member1()

{ ((Foo*)address)->Member1(); } И т.д. для остальных открытых функций

class RealFoo : public Foo { ... }; Foo* Foo::make()

return new FooPtr(new RealFoo, sizeof(RealFoo));

В клиентском коде class Bar { private:

Foo* foo; На самом деле невидимый указатель public:

Bar() : foo(Foo::make()) {}

Такое решение улучшает инкапсуляцию применения ведущих указателей. Кроме того, оно позволяет производящим функциям решить, какие экземпляры должны управляться подобным образом, а какие - с помощью обычных невидимых указателей или даже вообще без указателей. Все прекрасно работает, пока вы соблюдаете осторожность и выделяете в VoidPtrPool достаточно места для FooPtr. Помните, что из-за множественного наследования по сравнению с VoidPtr размер увеличивается, по крайней мере, на v-таблицу.

Объекты классов

Возможен и другой вариант - потребовать, чтобы все объекты происходили от общего класса-предка, способного возвратить объект класса для данного объекта или, по крайней мере, размер объекта. В этом случае вам уже не придется хранить в указателе объект экземпляра, поскольку его можно будет получить у объекта класса. Если вы готовы смириться с некоторым насилием в отношении типов в дескрипторах, это также позволит вам избежать шаблонов второго уровня, используемых для главных указателей. Вместо void* в VoidPtr можно будет хранить CommonBase* (где CommonBase - общий базовый класс). Мы избавляемся от переменной size, от необходимости иметь шаблон, производный от VoidPtr, и от виртуального деструктора в VoidPtr, и как следствие - от 4-байтового адреса v-таблицы. С другой стороны, если управляемые объекты уже содержат v-таблицы и не принуждают вас к применению множественного наследования, дополнительных затрат не будет.



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 [ 71 ] 72 73 74 75 76 77 78 79 80 81 82