Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 - [55]

Шрифт
Интервал

, имеет время жизни, управление которым осуществляется этими указателями посредством совместного владения. Никакой конкретный указатель >std::shared_ptr не владеет данным объектом. Вместо этого все указатели >std::shared_ptr, указывающие на него, сотрудничают для обеспечения гарантии, что его уничтожение произойдет в точке, где он станет более ненужным. Когда последний указатель >std::shared_ptr, указывающий на объект, прекратит на него указывать (например, из-за того, что этот >std::shared_ptr будет уничтожен или перенаправлен на другой объект), этот >std::shared_ptr уничтожит объект, на который он указывал. Как и в случае сборки мусора, клиентам не надо самим беспокоиться об управлении временем жизни объектов, на которые они указывают, но, как и при работе с деструкторами, время уничтожения объекта оказывается строго определенным.

Указатель >std::shared_ptr может сообщить, является ли он последним указателем, указывающим на ресурс, с помощью счетчика ссылок, значения, связанного с ресурсом и отслеживающего, какое количество указателей >std::shared_ptr указывает на него. Конструкторы >std::shared_ptr увеличивают этот счетчик (обычно увеличивают — см. ниже), деструкторы >std::shared_ptr уменьшают его, а операторы копирующего присваивания делают и то, и другое. (Если >sp1 и >sp2 являются указателями >std::shared_ptr, указывающими на разные объекты, присваивание “>sp1 = sp2;” модифицирует >sp1 так, что он указывает на объект, на который указывает >sp2. Конечным результатом присваивания является то, что счетчик ссылок для объекта, на который изначально указывал >sp1, уменьшается, а значение счетчика для объекта, на который указывает >sp2, увеличивается.) Если >std::shared_ptr после выполнения декремента видит нулевой счетчик ссылок, это означает, что на ресурс не указывает больше ни один >std::shared_ptr, так что наш интеллектуальный указатель освобождает этот ресурс.

Наличие счетчиков ссылок влияет на производительность.

• Размер >std::shared_ptr в два раза больше размера обычного указателя, поскольку данный интеллектуальный указатель содержит обычный указатель на ресурс и другой обычный указатель на счетчик ссылок[12].

• Память для счетчика ссылок должна выделяться динамически. Концептуально счетчик ссылок связан с объектом, на который он указывает, однако сам указываемый объект об этом счетчике ничего не знает. В нем нет места для хранения счетчика ссылок. (Приятным следствием этого является то, что интеллектуальный указатель >std::shared_ptr может работать с объектами любого типа (в том числе встроенных типов).) В разделе 4.4 поясняется, что можно избежать стоимости динамического выделения при создании указателя >std::shared_ptr с помощью вызова >std::make_shared, однако имеются ситуации, когда функция >std::make_shared неприменима. В любом случае счетчик ссылок хранится в динамически выделенной памяти.

• Инкремент и декремент счетчика ссылок должны быть атомарными, поскольку могут присутствовать одновременное чтение и запись в разных потоках. Например, >std::shared_ptr, указывающий на ресурс в одном потоке, может выполнять свой деструктор (тем самым уменьшая количество ссылок на указываемый им ресурс), в то время как в другом потоке указатель >std::shared_ptr на тот же объект может быть скопирован (а следовательно, увеличивает тот же счетчик ссылок). Атомарные операции обычно медленнее неатомарных, так что несмотря на то, что обычно счетчики ссылок имеют размер в одно слово, следует рассматривать их чтение и запись как относительно дорогостоящие операции.

Возбудил ли я ваше любопытство, когда написал, что конструкторы >std::shared_ptr “обычно” увеличивают счетчик ссылок для указываемого объекта? При создании >std::shared_ptr, указывающего на объект, всегда добавляется еще один интеллектуальный указатель >std::shared_ptr, так почему же счетчик ссылок может увеличиваться не всегда?

Из-за перемещающего конструирования — вот почему. Перемещающее конструирование указателя >std::shared_ptr из другого >std::shared_ptr делает исходный указатель нулевым, а это означает, что старый >std::shared_ptr перестает указывать на ресурс в тот же момент, в который новый >std::shared_ptr начинает это делать. В результате изменение значения счетчика ссылок не требуется. Таким образом, перемещение >std::shared_ptr оказывается быстрее копирования: копирование требует увеличения счетчика ссылок, а перемещение — нет. Это справедливо как для присваивания, так и для конструирования, так что перемещающее конструирование быстрее копирующего конструирования, а перемещающее присваивание быстрее копирующего присваивания.

Подобно >std::unique_ptr (см. раздел 4.1), >std::shared_ptr в качестве механизма удаления ресурса по умолчанию использует >delete, но поддерживает и пользовательские удалители. Однако дизайн этой поддержки отличается от дизайна для >std::unique_ptr. Для >std::unique_ptr тип удалителя является частью типа интеллектуального указателя. Для >std::shared_ptr это не так:

>auto loggingDel = [](Widget *pw) // Пользовательский удалитель

>{                                // (как в разделе 4.1)


Еще от автора Скотт Мейерс
Эффективное использование STL

В этой книге известный автор Скотт Мейерс раскрывает секреты настоящих мастеров, позволяющие добиться максимальной эффективности при работе с библиотекой STL.Во многих книгах описываются возможности STL, но только в этой рассказано о том, как работать с этой библиотекой. Каждый из 50 советов книги подкреплен анализом и убедительными примерами, поэтому читатель не только узнает, как решать ту или иную задачу, но и когда следует выбирать то или иное решение — и почему именно такое.


Как функции, не являющиеся методами, улучшают инкапсуляцию

Когда приходится инкапсулировать, то иногда лучше меньше, чем большеЯ начну со следующего утверждения: Если вы пишете функцию, которая может быть выполнена или как метод класса, или быть внешней по отношению к классу, Вы должны предпочесть ее реализацию без использования метода. Такое решение увеличивает инкапсуляцию класса. Когда Вы думаете об использовании инкапсуляции, Вы должны думать том, чтобы не использовать методы.Удивлены? Читайте дальше.


Рекомендуем почитать
Изучаем Java EE 7

Java Enterprise Edition (Java EE) остается одной из ведущих технологий и платформ на основе Java. Данная книга представляет собой логичное пошаговое руководство, в котором подробно описаны многие спецификации и эталонные реализации Java EE 7. Работа с ними продемонстрирована на практических примерах. В этом фундаментальном издании также используется новейшая версия инструмента GlassFish, предназначенного для развертывания и администрирования примеров кода. Книга написана ведущим специалистом по обработке запросов на спецификацию Java EE, членом наблюдательного совета организации Java Community Process (JCP)


Платформа J2Me

Эта книга научит вас, как разрабатывать программное обеспечение для платформы J2ME компании «Sun Microsystems». Эта книга придерживается стиля учебного пособия, это не справочное руководство.Цель — дать вам твердую основу в понятиях и техниках, которая даст вам возможность решиться на самостоятельную разработку качественных приложений.


Виртуальная библиотека Delphi

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Обработка баз данных на Visual Basic.NET

Это практическое руководство разработчика программного обеспечения на Visual Basic .NET и ADO.NET, предназначенное для создания приложений баз данных на основе WinForms, Web-форм и Web-служб. В книге описываются практические способы решения задач доступа к данным, с которыми сталкиваются разработчики на Visual Basic .NET в своей повседневной деятельности. Книга начинается с основных сведений о создании баз данных, использовании языка структурированных запросов SQL и системы управления базами данных Microsoft SQL Server 2000.


Исчерпывающее руководство по написанию всплывающих подсказок

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Программное обеспечение встроенных систем. Общие требования к разработке и документированию

Embedded system software. General requirements for development and documentationСтандарт подготовлен в развитие ГОСТ Р ИСО/МЭК 12207-99 «Информационная технология. Процессы жизненного цикла программных средств» с целью учета специфики разработки и документирования программного обеспечения встроенных систем реального времени.