А. Александреску - Современное проектирование на C++ (1119444), страница 43
Текст из файла (страница 43)
В главе рассмотрены четыре основные вариации на эту тему: синглтон, управляемый компилятором, феникс, синглтон с заданной продолжительностью жизни и бессмертный синглтон. У каждого из них есть свои преимушества и недостатки. Шаблон проектирования взпд1етоп тесно связан с моделями потоков, Шаблон поц!>1е-свес!с!пд ьоск!пд позволяет создать синглтоны, гарантируюшие безопасную работу потоков.
В заключении перечислены и классифицированы основные стратегии и выполнена соответствуюшая декомпозиция класса з)пд1етоп. В классе зз пд1етоп выделены три основные стратегии: сгеат!оп, ь!6ет!ве и тпгеаФпдмоде1, Этн стратегии сопряжены в определении класса зз од)есопно!бег с четырьмя параметрами (клиентский тип плюс три стратегии), которые покрывают все возможные комбинации проектных решений. 6.13. Краткое описание шаблонного класса 81пд1е1опйо1бег ° Определение класса Ыпд1етопно1дег имеет следуюший вид. тевр1аее < с1а55 Т, тевр1ате <с1азз> с1азз сгеат!опро1!су = сгеагецз!пднеи, сеир1ате <с1ааа> с1азз ь!Гет!пер)!су = пеКаи1ть!тес!ие, тевр1аге <с1азэ> с1азэ тпгеаоз пдмобе1 = в! пд)етпгеадео с1азз в!пд)етопно1оег; ° Шаблонный класс Б!пд1етопно1дег конкретизируется путем передачи клиентского класса в качестве первого шаблонного параметра.
!'азличные проектные варианты выбираются с помошью комбинирования четырех остальных параметров. с1азз мус1азз ( . туредеу з1пд1етоп<мус1аэз, сгеатезтатзс> муз!пд1ес1азз; > Нужно опрелелить конструктор по умолчанию или использовать для создания синглтона класс, отличаюшийся от стратегии Сгеатог, ° Готовые реализации трех основных стратегий описаны в табл. б.!.
При необходимости к ним можно добавить свои собственные классы стратегий, ориентированные на новые ограничения. Глава б, Реализация шаблона 8!пд!е)оп ИНТЕЛЛЕКТУАЛЬНЫЕ УКАЗАТЕЛИ Интеллектуальным указателям посвящены миллионы строк кода и сотни книг. Благодаря тому, что в интеллектуальных указателях переплелись многие синтаксические и семантические проблемы, они стали одной из самых популярных, интересных и мощных идиом языка С++.
В этой главе обсуждаются все аспекты интеллектуальных указателей (от простейших до самых сложных), а также наиболее распространенные ошибки, совершаемые программистами при их реализации. Интеллектуальные указа~ели — это объекты языка С++, имитирующие обычные указатели с помощью реализации оператора -> и унарного оператора *. Кроме того, они часто скрытно выполняют полезные задания (например, осуществляют управление памятью или блокировку), освобождая приложение от детального контроля за объектами, на которые они ссылаются.
В главе не только обсуждаются интеллектуальные указатели, но и реализован шаблонный класс 5вагсясг. Этот класс разработан на основе стратегий (глава 1). Он безопасен, эффективен и легок в использовании. Здесь рассмотрены следующие вопросы. ° Преимушества и недостатки интеллектуальных указателей.
° Стратегии управления владением. ° Неявные преобразования. ° Проверки и сравнения. ° Многопоточность. В главе описан обобщенный шаблонный класс ввагсятг. В каждом разделе рассматривается отдельная проблема, связанная с реализацией этого класса, а полная сборка класса выполняется в конце главы. Программисту мало знать, как устроен шаблонный класс 5еагсртг, нужно еше уметь использовать, изменять и расширять его в своих программах. 7.1. Сто первое описание интеллектуальных указателей Что такое интеллектуальный указатель? Это класс, имитирующий синтаксис и семантику обычного указателя и выполняющий много другой полезной работы. Поскольку интеллектуальные указатели, ссылающиеся на объекты разных типов, имеют много общего, они почти всегда реализуются в виде шаблонов.
тедр1ахе <с1ааз т> с1азз двагтрсг рцб1)с: Екр1(СЗт 5аастРСГ(ть рО)ПтЕЕ) : рОЗПтЕЕ (рОЗПСЕЕ); 5аагтртгй ОрЕГатог=(СОпзт 5аагтятгб осйег); -5аагтртг(); тб орегатог"О сопзт гетогп *розптее т* орегатог->О сопзт ( гетогп розптее ) ргзчасе: т* рочптее Шаблон 5аагтртг<т> хранит указатель на тип т в переменной-члене розптее .
Именно так поступает большинство интеллектуальных указагелей. В некоторых случаях в этих классах предусматривается некоторая дополнительная обработка данных, а сам указатель вычисляется на лету. Синтаксис и семантика обычных указателей имитируются следуюшими операторами шаблонного класса 5аагтртг. с1а55 аеддет ( робззс: ЧОЗд ЕОПО; 5аагтрсг<и(ддет> 5р(пеп избдет); 5Р†>ГОП(); (>5Р).ГОПО; Помимо определения класса зр, класс 5аагтртг ничем не отличается от обычного указателя. В этом и заключается сушество интеллектуального указателя: обычные указатели можно заменить интеллектуальными, не внося коренных изменений в программу.
Таким образом, можно легко получить дополнительные преимушества. Возможность практически не изменять код при использовании интеллектуальных указателей в больших приложениях — очень привлекательное и важное свойство. Однако, как мы увидим ниже, не все так просто. 7.2. Особенности интеллектуальных указателей Может возникнуть вопрос: "Зачем нужны интеллектуальные указатели?".
Какую выгоду можно изыечь, заменив обычные указатели интеллектуальными? Все очень просто. Интеллектуальные указатели имеют семантику значений, а простые указатели — нет. Объект, имеюший семантику значений, — это объелт, который можно копировапьь и присваивапьь. Числа типа )пт — - прекрасный пример. Их можно свободно создавать, копировать и изменять. Указатель, который применяется лля перемешения по буферу, также имеет семантику значений — он инициализируется адресом первой ячейки буфера и перемешается по нему вперед, пока не достигнет конца.
По пути значения этого указателя можно копировать в другие переменные, сохраняя промежуточные результаты. 180 Часть И. Компоненты Однако работать с указателями на объекты, созданные с помошью оператора пеп, нужно совсем иначе. Допустим, мы написали следуюшее выражение. ызг)дет* р = пеп изг)дет; В атом случае переменная р не только указывает на объект класса изыдет, размешенный в памяти, но и владееа им. Это значит, что при выполнении оператора де1ете р соответствуюший объект класса изыдет будет уничтожен, а выделенная для него память освобождена. Таким образом, приведенный ниже код окажется неверным.
изг)дет+ Р = пегг и)одет; р = 0„ // присваиваем указателю р нечто иное Это происходит потому, что мы теряем владение объектом, на который ранее ссылался указатель р, и не имеем возможности вернуть его, Это приводит к утечке ресурсов. Более того, при копировании указателя р в другую переменную компилятор не передает ей автоматически владение участком памяти, на который ссылается указатель. Вместо этого в программе появляются два указателя, содержащих адрес одного и того же объекта.
Это нежелательно, поскольку может привести к повторному удалению уже удаленного объекта (со всеми вытекающими катастрофическими последствиями). Следовательно, указатели на динамически размешаемые объекты не должны иметь семантики значениИ вЂ” - их нельзя копировать и присваивать как попало. Вот здесь-то и нужны интеллектуальные указатели. Большинство интеллектуальных указателей, помимо имитации простых указателей, управляют владеяяем объектами, на которые они ссылаются.
Они распознают изменения в правах владения, а их деструкторы освобождают память, следуя тшательно пролуманной стратегии. Во многих интеллектуальных указателях содержится достаточно информации, чтобы правильно освободить память, занятую объектом, на который они ссылаются.
Управление владением осуществляется разными способами в зависимости от решаемой задачи. Некоторые интеллектуальные указатели автоматически передают права на владение обьектом: после копирования исходному указателю присваивается нулевой адрес, а результируюшему — адрес обьекта и права на влаление. Именно такая стратегия реализована в стандартном интеллектуальном указателе зтд::авто ртг.
Другие интеллектуальные указатели используют подсчет ссылок: они отслеживают общее количество интеллектуальных указателей, ссылаюшихся на один и тот же объект, и, когда счетчик обнуляется, удаляют его. В заключение заметим, что сушествуют интеллектуальные указатели, при копировании которых создается дубликат объекта.
Владение объектом — важное свойство интеллектуальных указателей. Управляя правами владения, интеллектуальные указатели гарантируют целостность и полноценную семантику значений. Поскольку права владения связаны в основном с созданием, копированием и уничтожением интеллектуальных указателей, соответствуюшие функции-члены наиболее важны. В следуюших разделах мы рассмотрим разные аспекты разработки и реализации интеллектуальных указателей. Нашей целью будет максимально полная имитация простых указателей, но не будем забывать, что интеллектуальный указатель — более широкое понятие.
Между интеллектуальными и обычными указателями существует тонкая грань, отделяюшая полный контроль от хаоса. Мы увидим, что добавление на первый взгляд полезных свойств иногда оказывается весьма опасным. При реализации хороших интеллектуальных указателей следует соблюдать точный баланс. Глава 7. Интеллектуальные указатели 181 7.3. Хранение интеллектуальных указателей Для начала зададимся фундаментальным вопросом; "Должна ли переменная ро)псее иметь тип т*?".