Программирование >>  Синтаксис инициирования исключений 

1 ... 75 76 77 [ 78 ] 79 80 81 82


SH(const WH<Type>& h) : pointer(h.pointer) { pointer->Grab(); } operator WH<Type>() { return WH<Type>(pointer); } SH<Type>& operator=(const SH<Type>& h)

if (this == &h) return *this;

if (pointer == h.pointer) return *this;

pointer->Re1ease();

h.pointer->Grab();

return *this;

BMP<Type>& operator->() { return *pointer; }

Шаблон используется для обычных переменных (а не для переменных класса), ссылающихся на объекты. Благодаря конструктору, принимающему H<Type>, и операторной функции operator H<Type>() он также может использоваться в операциях присваивания с участием переменных классов, то есть слабых дескрипторов.

class Bar { private:

WH<Foo> foo; public:

void f();

void Bar::f()

SH<Foo> f; Эквивалентно Foo* f = new Foo;

f = foo; Использует operator=(SH<Type>(foo));

foo = f; Использует operator WH<Type>(f);

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

Помните VoidPtrIterator? VoidPtrPool возвращает один итератор для перебора всех указателей с ненулевыми счетчиками ссылок. Все остается без изменений, однако счетчик ссылок теперь интерпретируется по-другому. Раньше ненулевой счетчик ссылок означал, что объект не следует уничтожать. Теперь он имеет более узкое значение: объект доступен непосредственно из стека. Все эти объекты сохраняются, поскольку они находятся на периметре, но мы также сохраним объекты с нулевыми счетчиками ссылок, если они доступны косвенно.

Для объектов внутри периметра мы должны перебрать дескрипторы каждого объекта периметра, а затем рекурсивно двигаться внутрь до тех пор, пока не будут перебраны все доступные объекты. Для этого нам придется анализировать объекты одним из описанных выше способов. В данном примере будет использовано сочетание виртуальных функций/итераторов. Для этой цели можно слегка переработать старый интерфейс VoidPtrIterator .

class VoidPtrIterator { protected:

VoidPtrIterator() {} public:

virtual bool More() = 0;

virtual VoidPtr* Next() = 0;

Теперь пул должен поддерживать два типа итераторов. Один итератор перебирает указатели, находящиеся на периметре (то есть имеющие ненулевые счетчики ссылок). Второй - указатели на



объекты, находящиеся в указанной половине. Итератор VoidPtrPoo1::iterator() из главы 15 заменяется следующим:

Включить в класс VoidPtrPool

class VoidPtrPool {

public:

VoidPtrIterator* Reachab1e()

{ return new ReachableIterator(this); } VoidPtrIterator* InRange(void* low, void* high)

{ return new RangeIterator(this); }

Указатели периметра

Один из типов итераторов, возвращаемых пулом, перебирает непосредственно доступные указатели (имеющие ненулевой счетчик ссылок). В сущности, перед нами тот же VoidPtrPoolIterator с одной изменившейся строкой - теперь Advance() пропускает позиции с нулевым счетчиком ссылок. Класс реализован как производный от VoidPtrPoolIterator.

class ReachableIterator : public VoidPtrPoolIterator { protected:

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

VoidPtrPoolIterator::Advance(); while (block != NULL && b1ock->s1ots[s1ot].refcount == 0);

public:

Reachab1eIterator(VoidPtrBlock* vpb) : VoidPtrPoolIterator(vpb) {}

Недоступные указатели

В конце цикла мы должны пройтись по ведущим указателям и найти все те, которые продолжают ссылаться на неактивную половину. Это и будут недоступные объекты. Задачу решает следующий итератор, в котором используется очередное тривиальное переопределение VoidPtrPool Iterator.

class InRange : public VoidPtrPoolIterator { private:

void* low; Нижний адрес диапазона void* high; Верхний адрес диапазона

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

VoidPtrPoolIterator::Advance(); while (block != NULL &&

(b1ock->s1ots[s1ot].address < low b1ock->s1ots[s1ot].address >= high));

public:

InRange(VoidPtrBlock* vpb, void* 1ow addr, void* high addr)

: VoidPtrPoolIterator(vpb), 1ow(1ow addr), high(high addr) {}



Перебор указателей в объектах

Каждый объект возвращает другой итератор VoidPtrIterator , который перебирает указатели, доступные непосредственно из объекта. Для каждого класса этот итератор должен быть своим. Далее показан пример.

class MotherOfAllObject { Базовый класс для всех остальных public:

virtual VoidPtrIterator* Pointers() = 0;

template <c1ass Type>

class VoidPtrArrayIterator : public VoidPtrIterator { private:

VoidPtr* ptrs[Entries];

int next; Следующая позиция в переборе

public:

VoidPtrArrayIterator() : next(0)

for (int i = 0; i < Entries;

ptrs[i] = NULL;

VoidPtr*& operator[](uint slot) { return ptrs[s1ot]; } virtual bool More() { return next < Entries; } virtual VoidPtr* Next() { return ptrs[next++]; }

Пример класса и итератора

class Foo {

private:

WH<Bar> bar; public:

virtual VoidPtrIterator* Pointers()

new VoidPtrArrayIterator<1>* iterator = new VoidPtrArrayIterato<1>; iterator[0] = bar.Pointer(); return iterator;

VoidPtrArrayIterator сделан на скорую руку и в реальном проекте его использовать не стоит, но по крайней мере он демонстрирует общий принцип. Конечно, его следует дополнить проверками диапазонов и инициированием исключений, если будет затребован VoidPtr* для NULL. Foo::Pointers() показывает общий принцип использования VoidPtrArrayIterator . Для каждого класса мы изменяем размер массива, чтобы он совпадал с количеством WH<Widget> и добавляем для каждого дескриптора по одной строке вида iterator(index++) = widget.Pointer(). Этот шаблон справляется со всеми простыми случаями, в которых нам не приходится беспокоиться о базовых классах. Если Foo имеет базовые классы, придется организовать вложение итераторов для его собственных указателей и указателей базовых классов.

Перебор указателей

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



1 ... 75 76 77 [ 78 ] 79 80 81 82

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика