- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Язык программирования C++. Пятое издание - Стенли Липпман
Шрифт:
Интервал:
Закладка:
При выходе из функции, обычном или в связи с исключением, удаляются все ее локальные объекты. В данном случае указатель sp имеет тип shared_ptr, поэтому при удалении проверяется его счетчик ссылок. В данном случае sp — единственный указатель на контролируемую им область памяти, поэтому она освобождается в ходе удаления указателя sp.
Память, контролируемая непосредственно, напротив, не освобождается автоматически, когда происходит исключение. Если для управления памятью используются встроенные указатели и исключение происходит после оператора new, но перед оператором delete, то контролируемая память не будет освобождена:
void f() {
int *ip = new int(42); // динамически зарезервировать новый объект
// код, передающий исключение, не обрабатываемое в функции f()
delete ip; // освобождает память перед выходом
}
Если исключение происходит между операторами new и delete и не обрабатывается в функции f(), то освободить эту память никак не получится. Вне функции f() нет указателя на эту память, поэтому нет никакого способа освободить ее.
Интеллектуальные указатели и классы без деструкторовБольшинство классов языка С++, включая все библиотечные классы, определяют деструкторы (см. раздел 12.1.1), заботящиеся об удалении используемых объектом ресурсов. Но не все классы таковы. В частности, классы, разработанные для использования и в языке С, и в языке С++, обычно требуют от пользователя явного освобождения всех используемых ресурсов.
Классы, которые резервируют ресурсы, но не определяют деструкторы для их освобождения, подвержены тем же ошибкам, которые возникают при самостоятельном использовании динамической памяти. Довольно просто забыть освободить ресурс. Аналогично, если произойдет исключение после резервирования ресурса, но до его освобождения, программа потеряет его.
Для управления классами без деструкторов зачастую можно использовать те же подходы, что и для управления динамической памятью. Предположим, например, что используется сетевая библиотека, применимая как в языке С, так и в С++. Использующая эту библиотеку программа могла бы содержать такой код:
struct destination; // представляет то, с чем установлено соединение
struct connection; // информация для использования соединения
connection connect(destination*); // открывает соединение
void disconnect(connection); // закрывает данное соединение
void f(destination &d /* другие параметры */) {
// получить соединение; не забыть закрывать по завершении
connection с = connect(&d); // использовать соединение
// если забыть вызывать функцию disconnect() перед выходом из
// функции f(), то уже не будет никакого способа закрыть соединение
}
Если бы у структуры connection был деструктор, то по завершении функции f() он закрыл бы соединение автоматически. Однако у нее нет деструктора. Эта проблема почти идентична проблеме предыдущей программы, использовавшей указатель shared_ptr, чтобы избежать утечек памяти. Здесь также можно использовать указатель shared_ptr для гарантии правильности закрытия соединения.
Использование собственного кода удаленияПо умолчанию указатели shared_ptr подразумевали, что они указывают на динамическую память. Следовательно, когда указатель shared_ptr удаляется, он по умолчанию выполняет оператор delete для содержащегося в нем указателя. Чтобы использовать указатель shared_ptr для управления соединением connection, следует сначала определить функцию, используемую вместо оператора delete. Должна быть возможность вызова этой функции удаления (deleter) с указателем, хранимым в указателе shared_ptr. В данном случае функция удаления должна получать один аргумент типа connection*:
void end_connection(connection *p) { disconnect(*p); }
При создании указателя shared_ptr можно передать необязательный аргумент, указывающий на функцию удаления (см. раздел 6.7):
void f(destination &d /* другие параметры */) {
connection с = connect(&d);
shared_ptr<connection> p(&c, end_connection);
// использовать соединение
// при выходе из функции f(), даже в случае исключения, соединение
// будет закрыто правильно
}
При удалении указателя p для хранимого в нем указателя вместо оператора delete будет вызвана функция end_connection(). Функция end_connection(), в свою очередь, вызовет функцию disconnect(), гарантируя таким образом закрытие соединения. При нормальном выходе из функции f() указатель p будет удален в ходе процедуры выхода. Кроме того, указатель p будет также удален, а соединение закрыто, если произойдет исключение.
Внимание! Проблемы интеллектуального указателяИнтеллектуальные указатели могут обеспечить безопасность и удобство работы с динамически созданной памятью только при правильном использовании. Для этого следует придерживаться ряда соглашений.
• Не используйте значение того же встроенного указателя для инициализации (переустановки) нескольких интеллектуальных указателей.
• Не используйте оператор delete для указателя, возвращенного функцией get().
• Не используйте функцию get() для инициализации или переустановки другого интеллектуального указателя.
• Используя указатель, возвращенный функцией get(), помните, что указатель станет недопустимым после удаления последнего соответствующего интеллектуального указателя.
• Если интеллектуальный указатель используется для управления ресурсом, отличным от области динамической памяти, зарезервированной оператором new, не забывайте использовать функцию удаления (раздел 12.1.4 и раздел 12.1.5).
Упражнения раздела 12.1.4Упражнение 12.14. Напишите собственную версию функции, использующую указатель shared_ptr для управления соединением.
Упражнение 12.15. Перепишите первое упражнение так, чтобы использовать лямбда-выражение (см. раздел 10.3.2) вместо функции end_connection().
12.1.5. Класс unique_ptr
Указатель unique_ptr "владеет" объектом, на который он указывает. В отличие от указателя shared_ptr, только один указатель unique_ptr может одновременно указывать на данный объект. Объект, на который указывает указатель unique_ptr, удаляется при удалении указателя. Список функций, специфических для указателя unique_ptr, приведен в табл. 12.4. Функции, общие для обоих указателей, приведены в табл. 12.1.
В отличие от указателя shared_ptr, нет никакой библиотечной функции, подобной функции make_shared(), которая возвращала бы указатель unique_ptr. Вместо этого определяемый указатель unique_ptr связывается с указателем, возвращенным оператором new. Подобно указателю shared_ptr, можно использовать прямую форму инициализации:
unique_ptr<double> p1; // указатель unique_ptr на тип double
unique_ptr<int> p2(new int(42)); // p2 указывает на int со значением 42
Таблица 12.4. Функции указателя unique_ptr (см. также табл. 12.1)
unique_ptr<T> u1 unique_ptr<T, D> u2 Обнуляет указатель unique_ptr, способный указывать на объект типа Т. Указатель u1 использует для освобождения своего указателя оператор delete; а указатель u2 — вызываемый объект типа D unique_ptr<T, D> u(d) Обнуляет указатель unique_ptr, указывающий на объекты типа Т. Использует вызываемый объект d типа D вместо оператора delete u = nullptr Удаляет объект, на который указывает указатель u; обнуляет указатель u u.release() Прекращает контроль содержимого указателя u; возвращает содержимое указателя u и обнуляет его u.reset() u.reset(q) u.reset(nullptr) Удаляет объект, на который указывает указатель u. Если предоставляется встроенный указатель q, то u будет указывать на его объект. В противном случае указатель u обнуляетсяПоскольку указатель unique_ptr владеет объектом, на который указывает, он не поддерживает обычного копирования и присвоения:

