231
{
active = &A;
inactive
=
&B;
}
active->Reinitialize();
//
Перебрать все VoidPtr и найте активные объекты
VoidPtrIterator* iterator = VoidPtr::pool->iterator();
while
(iterator->More())
{
VoidPtr* vp = iterator->Next();
if (vp->address >= inactive &&
vp->address < inactive + sizeof(*inactive))
{
void*
new_space
=
active->Allocate(vp->size);
if (new_space == NULL)
// Исключение – нехватка памяти
memcpy(new_space,
vp->address,
vp->size);
vp->address
=
new_space;
}
}
delete
iterator;
}
Все существенное происходит в цикле
while
функции
Space::Swap()
. Каждый объект в
предыдущей, ранее активной половине копируется в новую активную половину. Вскоре вы поймете,
зачем мы проверяем, принадлежит ли адрес старой половине.
Оператор new
Конечно, у нас появляется перегруженный оператор
new
, который использует эту структуру.
void* operator new(size_t size, Space* space)
{
return
space->Allocate(size);
}
Ведущие указатели
Наконец, ведущие указатели должны использовать это пространство при создании объектов.
template
class BMP : public VoidPtr {
private: // Запретить копирование и присваивание указателей
BMP(const MP&) {}
BMP& operator=(const BMP&) { return *this; }
public:
BMP() : VoidPtr(new(object_space) Type, sizeof(Type)) {}
virtual ~BMP() { ((Type*)address->Type::~Type(); }
Type* operator->() { return (Type*)address; }
};
Здесь
object_space
— глобальная переменная (а может быть, статическая переменная класса
VoidPtr
), которая ссылается на рабочее пространство
Space
.
232
Последовательное копирование
Функция
Swap()
вызывается в произвольные моменты и, скорее всего, будет работать в течение
некоторого времени. В работе программы возникают непредсказуемые затяжки, а это бесит
пользователей едва ли не больше, чем аппаратные сбои. К счастью, алгоритм Бейкера легко
модифицировать, чтобы копирование выполнялось поэтапно в фоновом режиме.
На мосту Бей-Бридж в Сан-Франциско постоянно работает бригада маляров. Она начинает красить
мост с одного конца и через пару лет успешно докрашивает до другого. К этому времени можно
начинать красить заново, в другую сторону. Работа идет постоянно, не считая редких перерывов из-за
землетрясений или демонстраций протеста. В сущности, именно так алгоритм Бейкера превращается в
схему последовательного уплотнения.
Начинаем следующий заход на класс
Space
. Функция
Swap()
делится на две части, одна из которых
переключает активные половины, а другая многократно вызывается и при каждом вызове копирует по
одному объекту.
class Space {
private:
VoidPtrIterator*
iterator; //
Информация о копировании
HalfSpace A, B;
HalfSpace*
active;
HalfSpace*
inactive;
void
Swap();
//
Переключить активную половину, скопировать объекты
public:
Space() : active(&A), inactive(&B), iterator(NULL) { Swap(); }
void*
Allocate(size_t
size);
void
Copy1();
};
void* Space::Allocate(size_t size)
{
void* space = active->Allocate(size);
if (space != NULL)
//
Исключение – нехватка памяти
return
space;
}
void Space::Swap()
{
if (active == &A)
{
active = &B;
inactive
=
&A;
}
else
{
active = &A;
inactive
=
&B;
}
active->Reinitialize();
delete
iterator;
iterator
=
VoidPtr::pool->iterator();
}
void Space::Copy1()
Do'stlaringiz bilan baham: |