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



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

 
213 
CMP operator->() { return *pointee; } 
}; 
Если использовать дескрипторы в сочетании с ведущими указателями, можно выбрать, для каких 
экземпляров класса следует подсчитывать ссылки, а какие экземпляры должны управляться другим 
способом. 
Трудности подсчета ссылок 
Все выглядит так просто; однако без ложки дегтя дело все же не обходится. Подсчет ссылок обладает 
одним очень распространенным недостатком — зацикливанием. Представьте себе ситуацию: объект А 
захватил объект В (то есть вызвал для него функцию 
Grab()
), а объект В сделал то же самое для 
объекта А. Ни на А, ни на В другие объекты не ссылаются. Здравый смысл подсказывает, что А следует 
удалить вместе с В, но они продолжают существовать, поскольку их счетчики ссылок так и не 
обнуляются. Обидно, да? 
Подобное зацикливание возникает сплошь и рядом. Оно может относиться не только к парам объектов, 
но и целым подграфам. A 
->

->

->

->
A, но никто за пределами этой группы не ссылается ни на 
один из этих объектов. Группа словно плывет на «Летучем Голландце», построенном в эпоху высоких 
технологий и обреченном на вечные скитания в памяти. Существует несколько стратегий борьбы с 
зацикливаниями. Все они не обладают особой универсальностью, и в вашей конкретной ситуации это 
может привести к отказу от подсчета ссылок. Как правило, встречаясь с проблемой циклических 
ссылок, стоит рассмотреть более хитроумные приемы, описанные в двух последних главах. Как видите, 
мысль об отказе от подсчета ссылок приходит довольно быстро. 
Декомпозиция 
Предположим, А захватывает В, а затем В захватывает некоторый компонент А: 
class A { 
private: 
Foo* 
foo; 
B* 
b; 
}; 
Если сделать так, чтобы В выполнял захват в функции 
foo
, проблем не возникает. Когда последняя 
ссылка на A ликвидируется, его счетчик становится равным 0, поскольку В его не увеличивает. Для 
этого придется проявить некоторую изрядную изобретательность при кодировании, к тому же дизайн 
сильно зависит от особенностей конкретных объектов, но на удивление часто он решает проблему 
зацикливания. 
Сильные и слабые дескрипторы 
Предположим, ссылка А на В создавалась через 
Grab()
, а ссылка В на А — нет. В тот момент, когда 
исчезнет последняя ссылка на А из внешнего мира, подсчет ссылок для обоих объектов пары прекратит 
их существование. На этой идее основано различие между сильными (strong) и слабыми (weak) 
дескрипторами или указателями с подсчетом ссылок. Описанный выше шаблон 
CH
будет относиться к 
сильным дескрипторам, поскольку поддерживает счетчик ссылок. Обычный шаблон дескриптора (без 
вызова 
Grab
и 
Release
) будет относиться к слабым. Если спроектировать архитектуру объектов так, 
чтобы не существовало циклических подграфов, содержащих исключительно сильные дескрипторы, то 
вся схема подсчета ссылок снова возвращается в игру. Самая распространенная ситуация с таким 
решением — иерархия целое/часть, в которой пары удаляются при удалении целого. Целые 
поддерживают сильные ссылки, части — слабые. 
Подсчет ссылок и ведущие указатели 
Одно из самых распространенных и полезных применений подсчета ссылок заключается в управлении 
ведущими указателями. В предыдущих главах эта тема упоминалась неоднократно. Дескрипторы 
живут в стеке и потому автоматически уничтожаются при сборке мусора, выполняемой компилятором. 
Однако ведущие указатели (по тем же причинам, что и объекты) обычно приходится создавать в куче. 
Как узнать, когда следует удалять ведущий указатель? Подсчет ссылок упрощает эту задачу. 


 214 
Проблем с зацикливанием не будет: поскольку ведущий указатель не хранит ссылок на свои 
дескрипторы, связь является односторонней. Копируемые и передаваемые дескрипторы сохраняют 
длину в четыре байта без виртуальных функций, а лишь тривиальными подставляемыми функциями. 
Grab
и 
Release
съедают несколько дополнительных машинных тактов, но это мелочи по сравнению с 
тем, что вам пришлось бы проделывать для управления ведущима указателями без них. Несколько 
лишних байт для счетчика в ведущим указателе не играют особой роли; к тому же они выделяются в 
куче, степень детализации которой обычно заметно превышает четыре байта. 
Возможно, вам стоит вернуться к предыдущим главам и подумать, как использовать показанную схему 
подсчета ссылок везде, где встечаются ведущие указатели. Это станет ключом к нетривиальному 
управлению памятью в дальнейших главах. 
Пространтсва памяти 
Все эти фокусы образуют фундамент для дальнейшего строительства, но относить их к архитектуре 
было бы неверно. Для действительно нетривиального управления памятью понадобятся нетривиальные 
организационные концепции. В простейшем случае вся доступная память рассматривается как один 
большой блок, из которого выделяются блоки меньшего размера. Для этого можно либо напрямую 
обратиться к операционной системе с требованием выделить большой блок памяти при запуске, либо 
косвенно, в конечном счете перепоручая работу операторным функциям 
::operator new
и 
::operator delete

В двух последних главах мы взглянем на проблему с нетривиальных позиций и поделим доступную 
память на пространства (memory spaces). Пространства памяти — это концепция; ее можно 
реализовать на основе практически любой описанной выше блочно-ориентированной схемы 
управления памятью. Например, в одном пространстве памяти может использоваться система 
напарников, а в другом — списки свободной памяти. Концепция представлена в следующем 
абстрактном базовом классе: 
class MemSpace { 
public: 
void* Allocate(size_t bytes) = 0; 
void Deallocate(void* space, size_t bytes) = 0; 
}; 
(Если ваш компилятор поддерживает обработку исключений, при объявлении обоих функций следует 
указать возможность инициирования исключений.) Некоторым пространствам памяти можно не 
сообщать в функции 
Deallocate()
размер возвращаемых блоков; для конкретных схем могут 
появиться другие функции, но минимальный интерфейс выглядит именно так. Возможно, также будет 
поддерживаться глобальная структура данных — коллекция всех 
MemSpace
(причины 
рассматриваются ниже). Коллекция должна эффективно отвечать на вопрос: «Какому пространству 
памяти принадлежит данный адрес?» По имеющемуся адресу объекта вы определяете пространство 
памяти, в котором он живет. 
В реализации пространств памяти могут быть использованы любые методики, описанные в 
предыдущей главе: 
• 
Глобальная перегрузка операторов 
new
и 
delete
(обычно не рекомендуется). 
• 
Перегрузка операторов 
new
и 
delete
на уровне класса. 
• 
Использование оператора 
new
с аргументами под руководством клиента. 
• 
Использование оператора 
new
с аргументами на базе ведущих указателей. 
Существует немало причин для деления памяти на пространства. Ниже описаны некоторые 
распространенные стратегии выбора объектов, которые должны находиться в одном пространстве 
памяти. 
Деление по классам 
В предыдущих главах мы говорили об объектах классов, но так и не ответили напрямую на вопрос: как 
определить класс объекта для имеющегося объекта? Простейшее решение — добавить переменную, 



Download 1,95 Mb.

Do'stlaringiz bilan baham:
1   ...   115   116   117   118   119   120   121   122   ...   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