|
Пространства объектов Половины представлены в виде пространств памяти для создания объектов. Класс 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. |
Copyright 2005. Климов Александр. All Right Reserved.