Уроки модуля (2/2)
std::weak_ptr
Хотя std::shared_ptr чрезвычайно полезен, использование исключительно совместного владения может привести к проблеме, известной как циклическая ссылка (или циклическая зависимость).
Если каждый из двух или более объектов содержит shared_ptr, указывающий на другой, создается замкнутый цикл. В этой ситуации счетчик ссылок ни на один из объектов никогда не достигнет нуля, что предотвращает освобождение памяти и вызывает утечку памяти.
Что такое std::weak_ptr
Чтобы разорвать циклы владения, стандартная библиотека предлагает std::weak_ptr. Это интеллектуальный указатель, который наблюдает за объектом, управляемым shared_ptr, но без увеличения счетчика ссылок.
Он не владеет ресурсом напрямую, поэтому не предотвращает его уничтожение.
#include <memory>
std::shared_ptr<int> shared = std::make_shared<int>(42);
std::weak_ptr<int> weak = shared; // Does not increment reference count!Проверка и доступ к ресурсу
Поскольку weak_ptr не владеет ресурсом, ресурс может быть освобожден в любое время (когда все связанные экземпляры shared_ptr выходят за пределы области действия).
Чтобы использовать наблюдаемый ресурс, мы должны:
- Проверьте, действителен ли он, с помощью
expired(). - Временно преобразуйте
weak_ptrвshared_ptrс помощью методаlock(). Если ресурс все еще активен,lock()возвращает действительныйshared_ptr, в противном случае он возвращает нулевой указатель (nullptr).
if (!weak.expired()) {
// lock() creates a temporary shared_ptr to ensure safe access
if (std::shared_ptr<int> sharedAccess = weak.lock()) {
std::cout << *sharedAccess << std::endl;
}
} else {
std::cout << "Resource deallocated!" << std::endl;
}Попробуйте сами
Объявите std::weak_ptr<int> с именем wPtr, инициализированный из sPtr. Затем распечатайте логический результат, возвращенный wPtr.expired(), используя std::cout.
Показать подсказку
Объявите `weak_ptr`, указывающий тот же универсальный тип `<int>`, и назначьте ему `sPtr` непосредственно.
Решение доступно после 3 попыток
Используйте метод lock() для wPtr, чтобы получить временный общий_ptr. Если операция завершилась успешно (указатель не равен нулю), выведите разыменованное значение.
Показать подсказку
Инициализируйте переменную внутри блока if, вызвав wPtr.lock(), затем распечатайте ресурс, разыменовав его звездочкой `*`.
Решение доступно после 3 попыток