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



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

 
207 
Обход деревьев, вычисление рекурсивных выражений в языках типа Prolog — эти и многие другие 
рекурсивные алгоритмы имеют показанную структуру. Размещение локальных объектов в стеке может 
ускорить выделение и освобождение памяти, но этот вариант часто непрактичен. Альтернативный 
вариант — создать пул, локальный для 
Eval()
, и уничтожить его целиком при выходе из 
Eval()
. В 
области действия 
Eval()
все временные объекты размещаются в этом пуле. 
void* operator new(size_t size, Pool* p) 

return 
p->Allocate(size); 

template  
class PoolP {
// Указатель, использующий пул 
private: 
Type* 
pointee; 
public: 
PoolP(Pool* p) : pointee(new(p) Type) {} 
~PoolP { pointee->Type::~Type(); } 
// 
Все остальное для ведущих указателей 
}; 
void Eval(Structure s) 

Pool 
p; 
// 
Объявляется в стеке! 
PoolP 
foo(&p); // 
Использует пул 
Eval(s.SomePart()); // 
Использует свой собственный пул 
f(p, 
s); 
// 
Вместо f(s); f будет использовать тот же пул 
// 
Деструктор p уничтожает все сразу 

Pool
может представлять собой любую разновидность пула памяти. Скорее всего, это «тупой» пул, 
который просто выделяет память снизу вверх и не беспокоится о возвращении памяти. Умный 
указатель 
PoolP
вызывает деструктор указываемого объекта, но не освобождает его память. На эту 
тему существует множество вариантов: 
• 
Обойтись без 
PoolP
. Либо пусть пул сам вызывает деструкторы содержащихся в нем объектов 
из своего собственного деструктора (для этого все они должны иметь общий базовый класс и 
виртуальный деструктор), либо вообще не вызывайте деструкторы. (О господи! Неужели я 
сказал это? Но довольно часто такой вариант работает; главное — не хвастайтесь этим 
подвигом на семинарах по С++.) 
• 
Назначить «текущий пул» в глобальной переменной или статической переменной класса, а 
затем перегрузить оператор 
new
для использования текущего пула, каким бы он ни был. При 
этом вам не придется передавать текущий пул всем подфункциям вроде упоминавшейся выше 
f()

• 
Предоставить средства для перемещения или копирования объектов из локального пула в то 
место, где они смогут жить вне области действия 
Eval()
. Эта тема выходит за рамки данной 
главы, а возможно, и книги, но для нее можно приспособить методику дескрипторов из 
следующей главы. 
Последний вариант используется в стратегиях управления памятью настолько сложных, что голова 
начинает болеть заранее, еще до подробного знакомства с темой. К счастью, все трудности 
обусловлены необходимостью выбора — стоит или не стоит перемещать объекты из-за возможных 
обращений к ним со стороны чего-то, пережившего данный блок. Этот вопрос не из области С++, он 
скорее относится к алгоритмам и структурам данных. 


 208 
Скрытая информация 
Многие менеджеры памяти выделяют несколько дополнительных байт в операторе 
new
, чтобы при 
вызове оператора 
delete
был использован правильный размер независимо от того, является 
деструктор виртуальным или нет. 
void* Foo::operator new(size_t bytes) 

size_t real_bytes = bytes + sizeof(size_t); 
unsigned char* space = (unsigned char*)::operator new(real_bytes); 
((size_t)space) 

real_bytes; 
return space + sizeof(size_t); 

Теперь информацию о размере можно использовать в операторе 
delete
или в любом другом месте, где 
вам захочется узнать настоящий размер. Тем не менее, при этой стратегии необходимо учесть ряд 
обстоятельств. 
Лишние затраты 
В зависимости от компилятора и операционной системы эта методика уже может использоваться 
незаметно для вас. Если вы самостоятельно добавите информацию о размере, она может 
продублировать уже хранящиеся сведения. Скорее всего, это произойдет при делегировании 
::operator new
на уровне объектов (см. выше). Такая методика приносит наибольшую пользу в 
сочетании с блочными схемами выделения памяти, она сокращает затраты 
::operator new
или 
calloc
для блока, а не для отдельного объекта. 
Оптимизация размера кванта 
Большое преимущество этой методики заключается в том, что вы можете выделить больше места, чем 
было запрошено. Как это? Может ли принести пользу выделение лишней неиспользуемой памяти? На 
самом деле может, если подойти к этому разумно. Один из возможных вариантов — всегда выделять 
память с приращением в n байт, где минимальное значение n равно 4. При это повышается вероятность 
того, что после удаления 17-байтового объекта занимаемое им место удастся использовать, скажем, для 
18- или 19-байтового объекта. Более изощренный подход состоит в выделении памяти по степеням 2, 
или, если вы относитесь к числу истинных гурманов управления памятью, — по числам Фибоначчи. 
Такие системы называются системами напарников (buddy systems), поскольку для каждого 
выделенного блока вы сможете найти его напарника (то есть другую половинку большого блока, из 
которого он был выделен) исключительно по размеру и начальному адресу. Появляется возможность 
эффективного воссоединения соседних освобожденных блоков. Если вы интересуетесь подобными 
вещами, в главе 16 рассматриваются основы системы напарников для степеней 2 в контексте 
автоматической сборки мусора. 
Другая информация 
Кроме размера блока может сохраняться и другая информация, например: 
• 
адрес объекта класса для данного объекта; 
• 
флаги блока (например, «флаг зомби», о котором будет рассказано ниже); 
• 
статистическая информация — например, время создания объекта. 
Списки свободных блоков 
Упрощенный список свободных блоков, приведенный в предыдущей главе, может использоваться 
только для объектов постоянного размера. Например, он не будет нормально работать с производными 
классами, в которых добавляются новые переменные, поскольку они будут иметь другой размер. Сам 
список тоже ограничивался одним размером; для передачи оператору 
delete
правильного размера 
требовались виртуальные деструкторы. Впрочем, создать более универсальные списки уже не так уж 
трудно. 



Download 1,95 Mb.

Do'stlaringiz bilan baham:
1   ...   112   113   114   115   116   117   118   119   ...   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