Программирование >>  Формирование пользовательского контейнера 

1 ... 11 12 13 [ 14 ] 15 16 17 ... 156


На практике вы можете собирать неиспользуемую память реже, к примеру, когда gclist достигнет

определенного размера или после того как определенное число указателей GCPtr выйдет за пределы области видимости или доступная память иссякнет.

Сбор мусора проводится каждый раз, когда объект типа GCPtr выходит за пределы области видимости. Эта операция выполняется деструктором -GCPtrо. Сначала просматривается список gclist для поиска адреса, на который указывает удаляемый объект типа GCPtr. Если он найден, то е(х> поле refcount уменьшается на единицу. Далее деструктор -GCPtr () вызывает функцию collect о для очистки любой неиспользуемой памяти (тех фрагментов, счетчики ссылок которых равны нулю).

Как утверждается в комментарии, размешенном в конце кода деструктора, для практических целей рекомендуется собирать мусор гораздо реже, чем в тестовой профамме, выполняюшей эту операцию, как только какой-либо объект типа GCPtr выйдет за пределы области видимости. Более редкий сбор мусора, как правило, эффективнее. Выбранная в книге частота сбора мусора объясняется нeoбxoдиfocтью иллюстрации этой операции.

Сбор мусора с помощью функции collectO

В функции collectO реализована непосредственная операция очистки неиспользуемой памяти. Далее приводится код функции.

Сбор мусора. Возвращает true, если хотя бы один объект был удален, template <class Т, int size> bool GCPtr<T, size>::collect О { bool memfreed = false;

#ifdef DISPLAY

cout Before garbage collection for ;

ShowlistO; #endif

list<GCInfo<T> >::iterator p; do {

Просматривает gclist для обнаружения указателей, ни на что не

/ / с СЫЛС1ЮЩИХС я.



Глава 2

for(p = gclist.beginO; p != gclist.endO; p++) { Если используется, то пропускается, if(p->refcount > 0) continue;

memfreed = true;

Удаляет неиспользуемый элемент из списка gclist. gclist.remove(*р);

Освобождает память, пока 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.endO);

#ifdef DISPLAY

cout After garbage collection for ;

showlistO ; #endif

return memfreed;



функция collectO ищет в списке gclist элементы, чье поле refcount равно нулю. Когда такой элемент найден, он удаляется из списка gclist с помощью вызова функции removeo, которая является членом класса list библиотеки STL. Затем память, связанная с этим элементом списка, освобождается.

Напоминаю, что в языке С++ одиночные объекты уничтожаются с помощью операции delete, а массивы - с помощью операции delete [ ]. Таким образом, значение поля isArray удаляемого элемента списка определяет, какая из названных операций применяется для очистки памяти. Это одна из причин, по которой вы должны задавать размер массива в любом объекте класса GCPtr, который указывает на массив, при этом поле isArray получает значение true. Если оно не установлено корректно, невозможно должным образом освободить выделенную память.

Хотя задача сбора мусора - очистка памяти в автоматическом режиме, вы можете, если необходимо, отчасти управлять этим процессом вручную. Функцию collectO можно вызвать прямо из пользовательского кода, потребовав выполнить сбор мусора. Обратите внимание, она описана в классе GCPtr как статическая функция. Это значит, что для ее вызова не нужна ссылка на какой-либо объект.

GCPtr<int>::collect о; собирает все неиспользуемые указатели типа int Приведенная строка вызовет сбор мусора в списке gclist<int>. Поскольку существуют разные списки gclist для различных типов указателей, следует вызывать функцию collect о для каждого списка, в котором нужно собрать мусор. Откровенно говоря, если вы хотите тщательно контролировать удаление динамически размещенных объектов, лучше воспользоваться системой распределения памяти вручную, реализованной в языке С++. Прямой вызов функции collectO большс вссго подходит для особых ситуаций, например, при неожиданном дефиците свободной памяти.

Перегрузка операций присваивания

Класс GCPtr перефужает operator=o дважды: первый раз для присваивания адреса его указателю, а второй раз для присваивания одного указателя класса ccptr другому указателю. Оба варианта приведены далее. Перегружает присваивание указателя объекту GCPtr. tenplate <class Т, int size> Т** GCPtr<T, size>: :operator=(T *t) { list<GCInfo<T> >::iterator p;

Во-первых, уменьшает на единицу счетчик ссылок для памяти, указываемой в данный момент. Р = findPtrlnfo(addr);



1 ... 11 12 13 [ 14 ] 15 16 17 ... 156

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