C++: библиотека программиста



Download 1,95 Mb.
Pdf ko'rish
bet117/144
Sana24.02.2022
Hajmi1,95 Mb.
#223123
TuriРеферат
1   ...   113   114   115   116   117   118   119   120   ...   144
Bog'liq
C -Eldjer-Djeff-for-Real-Programmers-RUS-www.itlibitum.ru

 
209 
Одно из несложных усовершенствований заключается в том, чтобы хранить в каждом узле списка не 
только адрес следующего указателя в списке, но и размер блока. Это позволит хранить в одном списке 
блоки разных размеров. При выделении памяти мы просматриваем список, пока не находим блок, 
размеры которого достаточны для наших целей. Для этого придется хранить скрытую информацию о 
размере блока даже после его выделения, чтобы при уничтожении объекта восстанавливать весь блок. 
Стратегия, прямо скажем, тупая и подходит разве что для очень маленьких списков, поскольку время 
поиска возрастает линейно с размером списка. Впрочем, она послужит отправной точкой для нашего 
обсуждения. 
Более эффективное представление — коллекция списков свободной памяти, в которой каждый список 
представляет блоки определенного размера. Ниже показана урощенная, но полезная реализация. 
class MemManager { 
private: 
struct 
FreeList 

// 
Список с блоками определенного размера 
FreeList* 
next; 
// 
Следующий FreeList 
void* 
top_of_list; 
// 
Верх текущего списка 
size_t 
chunk_size; 
// 
Размер каждого свободного блока 
FreeList(FreeList* successor, size_t size) : next(successor), 
top_of_list(NULL), 
chunk_size(size) 
{} 
}; 
FreeList* 
all_lists; 
// 
Список всех FreeList 
public: 
MemManager() : all_lists(NULL) {} 
void* 
Allocate(size_t 
bytes); 
void Deallocate(void* space, size_t bytes); 
}; 
void* MemManager::Allocate(size_t bytes) 

for (FreeList* fl = all_lists; 
fl != NULL && fl->chunk_size != bytes; 
fl = fl->next) 

if (fl->top_of_list != NULL) 

void* 
space 

fl->top_of_list; 
fl->top_of_list 

*((void**)(fl->top_of_list)); 
return 
space; 

return ::operator new(bytes); 
// Пустой список 

return ::operator new(bytes); 
// Такого списка нет 

void MemManager::Deallocate(void* space, size_t bytes) 

FreeList* fl = NULL; 
for (fl = all_lists; fl != NULL; fl = fl->next) 
if (fl->chunk_size == bytes) break; 
if (fl == NULL) 
// Списка для такого размера нет 

fl = new FreeList(all_lists, bytes); 
all_lists = fl; 


 210 

*((void**)space) = fl->top_of_list; 
fl->top_of_list 

space; 

Функции 
Allocate()
и 
Deallocate()
вызываются из перегруженных операторов 
new
и 
delete
соответственно. Такой подход предельно упрощен, но работает он неплохо. Вы можете 
воспользоваться им для любого сочетания классов, и он будет работать с производными классами, в 
которых добавились новые переменные. Он также может использоваться в схеме управления памятью 
на базе ведущих указателей. Существуют многочисленные усовершенствования, которые можно 
внести в показанную основу: 
• 
Ограничить размеры блоков числами, кратными некоторому числу байт, степенями 2 или 
числами Фибоначчи. 
• 
Воспользоваться более эффективной структурой данных, чем связанный список списков — 
возможно, бинарным деревом или даже массивом, если диапазон размеров невелик. 
• 
Предоставить функцию 
Flush()
, которая при нехватке памяти удаляет все содержимое 
списков. 
• 
В функции 
Allocate()
при отсутствии в списке свободного места заданного размера выделить 
память под массив блоков этого размера вместо одного блока. 
Подсчет ссылок 
Подсчет ссылок основан на простой идее — мы следим за количеством указателей, ссылающихся на 
объект. Когда счетчик становится равным 0, объект удаляется. Звучит просто, не правда ли? В 
определенных условиях все действительно просто, но подсчет ссылок обладает довольно жесткими 
ограничениями, которые снижают его практическую ценность. 
Базовый класс с подсчетом ссылок 
Начнем с абстрактного базового класса, от которого можно создать производный класс с подсчетом 
ссылок. Базовый класс содержит переменную, в которой хранится количество вызовов функции 
Grab()
за вычетом количества вызовов функции 
Release()

class RefCount { 
private: 
unsigned long count; 
// Счетчик ссылок 
public: 
RefCount() : count(0) {} 
RefCount(const RefCount&) : count(0) {} 
RefCount& 
operator=(const 
RefCount&) 
{ return *this; } // Не изменяет счетчик 
virtual 
~RefCount() 
{} 
// 
Заготовка 
void Grab() { count++; } 
void 
Release() 

if (count > 0) count --; 
if (count == 0) delete this; 

}; 
Пока клиентский код правильно вызывает функции 
Grab()
и 
Release()
, все работает абсолютно 
надежно. Каждый раз, когда клиент получает или копирует адрес объекта, производного от 
RefCount

он вызывает 
Grab()
. Когда клиент гарантирует, что адрес больше не используется, он вызывает 
Release()
. Если счетчик падает до 0 — бац! Нет больше объекта! 



Download 1,95 Mb.

Do'stlaringiz bilan baham:
1   ...   113   114   115   116   117   118   119   120   ...   144




Ma'lumotlar bazasi mualliflik huquqi bilan himoyalangan ©hozir.org 2024
ma'muriyatiga murojaat qiling

kiriting | ro'yxatdan o'tish
    Bosh sahifa
юртда тантана
Боғда битган
Бугун юртда
Эшитганлар жилманглар
Эшитмадим деманглар
битган бодомлар
Yangiariq tumani
qitish marakazi
Raqamli texnologiyalar
ilishida muhokamadan
tasdiqqa tavsiya
tavsiya etilgan
iqtisodiyot kafedrasi
steiermarkischen landesregierung
asarlaringizni yuboring
o'zingizning asarlaringizni
Iltimos faqat
faqat o'zingizning
steierm rkischen
landesregierung fachabteilung
rkischen landesregierung
hamshira loyihasi
loyihasi mavsum
faolyatining oqibatlari
asosiy adabiyotlar
fakulteti ahborot
ahborot havfsizligi
havfsizligi kafedrasi
fanidan bo’yicha
fakulteti iqtisodiyot
boshqaruv fakulteti
chiqarishda boshqaruv
ishlab chiqarishda
iqtisodiyot fakultet
multiservis tarmoqlari
fanidan asosiy
Uzbek fanidan
mavzulari potok
asosidagi multiservis
'aliyyil a'ziym
billahil 'aliyyil
illaa billahil
quvvata illaa
falah' deganida
Kompyuter savodxonligi
bo’yicha mustaqil
'alal falah'
Hayya 'alal
'alas soloh
Hayya 'alas
mavsum boyicha


yuklab olish