Модульні уроки (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, щоб отримати тимчасовий shared_ptr. Якщо операція виконана успішно (вказівник не є нульовим), надрукуйте розіменоване значення.
Показати підказку
Ініціалізуйте змінну всередині блоку «if», викликавши «wPtr.lock()», а потім надрукуйте ресурс із розіменуванням із зірочкою «*».
Рішення доступне після 3 спроб