По умолчанию указатели shared_ptr подразумевали, что они указывают на динамическую память. Следовательно, когда указатель shared_ptr удаляется, он по умолчанию выполняет оператор delete для содержащегося в нем указателя. Чтобы использовать указатель shared_ptr для управления соединением connection, следует сначала определить функцию, используемую вместо оператора delete. Должна быть возможность вызова этой shared_ptr. В данном случае функция удаления должна получать один аргумент типа connection*:
void end_connection(connection *p) { disconnect(*p); }
При создании указателя shared_ptr можно передать необязательный аргумент, указывающий на функцию удаления (см. раздел 6.7):
void f(destination &d /*
connection с = connect(&d);
shared_ptr
//
//
//
}
При удалении указателя p для хранимого в нем указателя вместо оператора delete будет вызвана функция end_connection(). Функция end_connection(), в свою очередь, вызовет функцию disconnect(), гарантируя таким образом закрытие соединения. При нормальном выходе из функции f() указатель p будет удален в ходе процедуры выхода. Кроме того, указатель p будет также удален, а соединение закрыто, если произойдет исключение.
Интеллектуальные указатели могут обеспечить безопасность и удобство работы с динамически созданной памятью только при правильном использовании. Для этого следует придерживаться ряда соглашений.
• Не используйте значение того же встроенного указателя для инициализации (переустановки) нескольких интеллектуальных указателей.
• Не используйте оператор delete для указателя, возвращенного функцией get().
• Не используйте функцию get() для инициализации или переустановки другого интеллектуального указателя.
• Используя указатель, возвращенный функцией get(), помните, что указатель станет недопустимым после удаления последнего соответствующего интеллектуального указателя.
• Если интеллектуальный указатель используется для управления ресурсом, отличным от области динамической памяти, зарезервированной оператором new, не забывайте использовать функцию удаления (раздел 12.1.4 и раздел 12.1.5).
Упражнение 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