Главная arrow С++ (часть 4) arrow Однопоточный сборщик мусора

Однопоточный сборщик мусора

#include <iostream> #include <list> #include <typeinfo> #include <cstdlib>
using namespace std;
// Для наблюдения за работой сборщика мусора определите DISPLAY.
// #define DISPLAY
// исключение генерируется при попытке использовать объект // Iter, выходящий за пределы диапазона // базового объекта. //
class OutOfRangeExc {
// Добавьте функциональные возможности, если они необходимы // для вашего приложения.
};
// Класс-итератор (iterator-like) для циклического перемещения
//в массивах, на которые указывают указатели GCPtr. Указатели Iter
//** не участвуют **в сборе мусора и не влияют на него.
// Следовательно, указание с помощью Iter
//на какой-либо объект не препятствует
// освобождению отведенной объекту памяти.
//
template <class Т> class Iter {
Т *ptr;     // значение текущего указателя
Т *end;     // указывает на элемент, следующий за последним элементом Т *begin; // указывает на начало распределенного массива unsigned length;// длина массива public:
Iter()  {
ptr = end = begin = NULL; length = 0;
}
Iter(T *pf T *first, T *last) { Ptr =   p; end = last; begin = first; length = lasc - first;
}
// Возвращает длину последовательности, на которую // этот Iter указывает.
unsigned size() { return length;   }
// Возвращает значение, на которое указывает ptr. //Не разрешает выход за пределы диапазона. Т &operator*() {
if{ (ptr >= end)  11  (ptr < begin) )
throw OutOfRangeExc();
return *ptr;
}
// Возвращает адрес, содержащийся в ptr.
// Препятствует выходу за пределы диапазона.
Т *operator->() {
if( (ptr >= end)  ||  (ptr < begin) ) throw OutOfRangeExc () ;
return ptr;
}
// Префикс ++. Iter operator++() { ptr++;
return *this;
}
// Префикс —. Iter operator—() { ptr—;
return *this;
}
// Постфикс ++.
Iter operator++(int notused) { T *tmp = ptr;
ptr++;
return Iter<T>(tmp, begin, end);
}
// Постфикс —.
Iter operator—(int notused) { T *tmp = ptr;
ptr—;
return Iter<T>(tmp, begin, end);
}
// Возвращает ссылку на объект
//с заданным индексом. Не разрешает выход
//за пределы диапазона.
Т &operator[](int i) {
if( (i < 0)  ||  (i >= (end-begin)) ) throw OutOfRangeExc () ;*
return ptr[i];
}
// Определяет операции отношения, bool operator==(Iter op2)  { return ptr == op2.ptr;
}
bool operator!=(Iter op2) { return ptr != op2.ptr;
}
bool operator<(Iter op2)  { return ptr < op2.ptr;
}
bool operacor<=(Iter op2)  { return ptr <= op2.ptr;
}
bool operator>(Iter op2)  { return ptr > op2.ptr;
}
bool operator>=(Iter op2)  { return per >= op2.ptr;
}
II Вычитает целое из Iter. Iter operator-(int n)  {
ptr -= n;
return *this;
}
// Прибавляет целое к Iter. Iter operator+(int n)    {
ptr += n;
return *this;
}
// Возвращает число элементов между двумя указателями Iter, int operator-(Iter<Т> &itr2)  { return ptr - itr2.ptr;
}
};
// Этот-класс определяет элемент, который запоминается
//в информационном списке сбора мусора.
//
template <class Т> class GClnfo { public:
unsigned refcount; // текущее число ссылок T *memPtr; // указатель на выделенную память
/* isArray равен true, если memPtr указывает на
размещенный массив. В противном случае false. */ bool isArray; // true, если указание на массив
/* Если memPtr указывает на размещенный
массив, то arraySize содержит его размер */ unsigned arraySize; // длина или размер массива
// Здесь mPtr указывает на выделенную память. // Если это массив, в size определяет // размер массива.
GCInfo(T *mPtr, unsigned size=0)    { refcount = 1; memPtr = mPtr; if(size != 0)
isArray = true; else
isArray = false; arraySize = size;
}
};
// Перегруженная операция == позволяет сравнивать объекты GCInfo. // Это необходимо для класса list библиотеки STL. template <class Т> bool operator==(const GCInfo<T> &obl, const GCInfo<T> &ob2)  { return (obl.memPtr == ob2.memPtr);
)
// GCPtr реализует тип указателя, применяющегося
// для сбора мусора и освобождающего неиспользуемую память.
// GCPtr должен использоваться только для указания на память,
// которая выделяется динамически с помощью new.
// Если применяется для ссылки на массив,
// определяет размер массива.
//
template <class Т, int size=0> class GCPtr   {
// gelist поддерживает список сбора мусора, static list<GCInfo<T> > gclist;
// addr указывает на выделенную память,.на которую // этот указатель GCPtr ссылается в данный момент. Т *addr;
/* isArray равен true, если этот GCPtr указывает
на размещенный массив. В противном случае равен false. */ bool isArray; // Равен true, если указание на массив.
II Если этот GCPtr указывает на размещенный динамически // массив, arraySize содержит размер массива, unsigned arraySize; // размер массива
static bool first; // Равен true, когда создается первый GCPtr.
// Возвращает iterator для указателя info в списке gclist. typename list<GCInfo<T> >::iterator findPtrInfo(T *pcr);
public:
// Определяет тип итератора для GCPtr<Т>. typedef Iter<T> GCiterator;
// Конструктор для инициализированных и неинициализированных
// объектов.
GCPtr(Т *t=NULL)    {
// Регистрирует shutdown() как функцию завершения, if(first) atexit(shutdown); first = false;
list<GCInfo<T> >::iterator p;
p = findPtrlnfo(t);
// Если t уже есть в списке gclist,
// увеличивает его счетчик ссылок.
// В противном случае добавляет его в список.
if(p != gclist.end())
p->refcount++; // увеличение счетчика ссылок else (
// Создает и запоминает новый элемент. GCInfo<T> gcObj(t. size); gclist.push_front(gcObj);
}
addr = t;
arraySize = size;
if(size > 0) isArray = true;
else isArray = false; #ifdef DISPLAY
cout « "Constructing GCPtr. "; if(isArray)
cout « " Size is " « arraySize « endl; else
cout « endl; #endif
}
// Копирующий конструктор. GCPtr (const GCPtr &ob)    {
list<GCInfo<T> >::iterator p;
p = findPtrlnfo(ob.addr);
p->refcount++; // увеличивает счетчик ссыпок на единицу
addr = ob.addr;
arraySize = ob.arraySize;
if(arraySize > 0) isArray = true;
else isArray = false;
#ifdef DISPLAY
cout « "Constructing copy.";
if(isArray)
cout « " Size is " « arraySize « endl;
else
cout « endl; #endif
}
// Деструктор для GCPTr. -GCPtr();
// Собирает мусор. Возвращает true, если хотя бы // один объект был удален, static bool collect();
// Перегружает присваивание указателя GCPtr. Т *operator=(T *t);
// Перегружает присваивание одного GCPtr другому GCPtr. GCPtr &operator=(GCPtr &rv);
// Возвращает ссылку на объект, на который // указывает этот GCPtr. Т &operator*()    { return *addr;
}
// Возвращает адрес, на который указывает. Т *operator->() { return addr;}
// Возвращает ссылку на объект //с индексом, заданным i. Т &operator[](int i)  { return addr[i];
}
// Функция преобразования для Т *. operator Т *() { return addr; }
// Возвращает Iter для начала выделенной памяти. Iter<T> begin()    { int size;
if(isArray) size = arraySize; else size = 1;
return Iter<T>(addr, addr, addr + size);
}
// Возвращает Iter для элемента, следующего за последним элементом // распределенного в памяти массива. Iter<T> end()    { int size;
if(isArray) size = arraySize; else size = 1;
return Iter<T>(addr + size, addr, addr + size);
}
// Возвращает размер gclist для этого типа GCPtr. static int gclistSizeO { return gel is t.sizeO ; }
// функция-утилита для отображения gclist. static void showlistO;
// Очищает gclist, когда программа завершается, static void shutdown();
};
// Выделяет память для статических переменных template <class Т,  int size>
list<GCInfo<T> > GCPtr<T, size>:rgcliet;
template <class T, int size>
bool GCPtrcT, size>::first = true;
// Деструктор для GCPtr. template <class T, int size> GCPtr<T, size>::-GCPtr()    { list<GCInfo<T> >::iterator p;
p = findPtrInfo(addr);
if(p->refcount) p->refcount—; // уменьшает счетчик // ссылок на единицу
#ifdef DISPLAY
cout « "GCPtr going out of scope.\n"; #endif
// Собирает мусор, когда указатель выходит за пределы области // видимости, collect();
//На практике вы можете захотеть собирать
II неиспользуемую память реже, к примеру, когда gclist достигнет // определенного размера или после того как определенное число // указателей GCPtr выйдет за пределы области^видимости, // или когда доступная память иссякнет.
}
// Сбор мусора. Возвращает true, если хотя бы // один объект был удален, template <class Т, int size> bool GCPtr<T. size>::collect()  { bool memfreed = false;
#ifdef DISPLAY
cout « "Before garbage collection for ";
showlist(); #endif
list<GCInfo<T> >::iterator p; do {
// Просматривает gclist для обнаружения указателей, // ни на что не ссылающихся.
for(p = gclist.begin(); р != gclist.end(); р++)  { // Если используется, пропустить, if(p->refcount > 0) continue;
memfreed = true;
// Удаляет неиспользуемый элемент из списка gclist. gclist.remove(*p);
// Освобождает память, пока GCPtr не станет равным null, if (p->memPtr)  { if(p->isArray)  { #ifdef DISPLAY
cout « "Deleting array of size " « p->arraySize « endl;
#endif
delete[] p->memPtr; // удаляет массив
}
else {
#ifdef DISPLAY
cout « "Deleting: "
"« *(T *) p->memPtr « "\n";
#endif
delete p->memPtr; // удаляет единичный элемент
}
}
// Возобновляет поиск, break;
}
} while(р != gclist.end());
#ifdef DISPLAY
cout « "After garbage collection for ";
showlist(); #endif
return memfreed;
}
// Перегружает присваивание указателя GCPtr. template <class T, int size> T " GCPtr<T, size>::operator=(T *t)  { list<GCInfo<T> >::iterator p;
// Во-первых, уменьшает на единицу счетчик ссылок
// для области памяти, на которую указывает в данный момент.
Р = findPtrlnfo(addr);
p->refcount—;
// Далее, если новый адрес уже
// существует в системе, увеличивает
// его счетчик ссыпок. В противном случае создает новый // элемент в списке gclist. Р = findPtrlnfo(t);
if(p != gclist.end())
p->refcount++; else {
// Создает и запоминает новый элемент. GCInfo<T> gcObj(t, size); gclist.push_front(gcObj);
>
addr = t; // запоминает адрес, return t;
}
// Перегружает присваивание одного GCPtr другому GCPtr. template <class T, int size>
GCPtr<T, size> & GCPtr<T, size>::operator=(GCPtr &rv)  { list<GCInfo<T> >::iterator p;
// Сначала уменьшает на единицу счетчик ссылок // для памяти, указываемой в данный момент, р = findPtrInfo(addr); p->refcount—;
// Далее увеличивает счетчик ссылок для
// нового адреса.
р = f indPtr Info (rv. addr) ,-
p->refcount++; // увеличивает счетчик ссылок addr = rv.addr;// запоминает адрес, return rv;
}
// Функция-утилита для отображения списка gclist. template <class T, int size> void GCPtr<T, size>::showlist()  { list<GCInfo<T> >::iterator p;
cout « "gclist<" « typeid(T) .nameO «       "
« size « ">:\n";
cout « "memPtr      refcount       value\n";
if(gclist.begin() == gclist.end()) { cout « " — Empty —\n\n" ; return;
}
for(p = gclist.begin(); p != gclist.end(); p++) { cout «   "[" « (void *)p->memPtr « "]"
« " " « p->refcount « " ";
if(p->memPtr) cout « "     " « *p->memPtr;
else cout « "     ---";
cout « endl;
}
cout « endl;
}
// Находит указатель в списке gclist. template <class T, int size> typename list<GCInfo<T> >::iterator GCPtr<T, size>::findPtrInfo(T *ptr)  {
list<GCInfo<T> >::iterator p;
// Находит ptr в gclist.
for(p = gclist.beginO ; p != gclist.end(); p++) if(p->memPtr == ptr) return p;
return p;
}
11 Очищает gclist, когда программа завершается.
template <class T, int size>
void GCPtr<T, size>::shutdown()    {
if (gclistSizeO == 0) return; // список пуст
list<GCInfo<T> >::iterator р;
for(p = gclist.begin(); p != gclist.end(); p++) { // Устанавливает все счетчики ссылок в ноль. p->refcount = 0;
}
#ifdef DISPLAY
cout « "Before collecting for shutdown() for " « typeid(T).name() « "\n";
#endif collect(); #ifdef DISPLAY
cout « "After collecting for shutdown() for "
« typeid(T).name() « "\n"; #endif
}