Материалы книги получены с http://www.itlibitum.ru/
Пространства объектов
Половины представлены в виде пространств памяти для создания объектов. Класс HalfSpace
изображает одну половину, а Space - всю память, видимую клиентам.
Класс HalfSpace
Каждая половина по отдельности выглядит как обычное пространство памяти со специализированной функцией Allocate(). Парная функция Deallocate() не понадобится.
class HalfSpace {
private:
unsigned long next_byte; // Следующий выделяемый байт
unsigned char bytes[HALFSIZE];
public:
HalfSpace() : next_byte(0) {}
void* Allocate(size_t size);
void Reinitialize() { next_byte = 0; }
};
void* HalfSpace::Allocate(size_t size)
{
// Выровнять до границы слова
size = ROUNDUP(size);
if (next_byte + size >= HALFSIZE)
return NULL; // Не хватает памяти
void* space = &bytes[next_byte];
next_byte += size;
return space;
}
Класс Space
Общий пул представляет собой совокупность двух половин. Он также имеет функцию Allocate(), которая в обычных ситуациях просто поручает работу активной половине. Если в активной половине не найдется достаточно памяти, происходит переключение половин и копирование активных объектов в другую половину функцией Swap(). Эта схема основана на предыдущем материале - специализированном пуле VoidPtr со средствами перебора.
class Space {
private:
HalfSpace A, B;
HalfSpace* active;
HalfSpace* inactive;
void Swap(); // Переключить активную половину, скопировать объекты
public:
Space() : active(&A), inactive(&B) {};
void* Allocate(size_t size);
};
void* Space::Allocate(size_t size)
{
void* space = active->Allocate(size);
if (space != NULL) return space;
Swap();
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();
// Перебрать все 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 Type>
class BMP : public VoidPtr {
private: // Запретить копирование и присваивание указателей
BMP(const MP<Type>&) {}
BMP<Type>& operator=(const BMP<Type>&) { 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.
Назад Содержание Далее
|