Lekcje modułu (2/2)
std::weak_ptr
Chociaż std::shared_ptr jest niezwykle użyteczny, wyłączne korzystanie z własności współdzielonej może prowadzić do problemu znanego jako referencja cykliczna (lub zależność cykliczna / cyclic dependency).
Jeśli dwa lub więcej obiektów zawiera shared_ptr wskazujący na siebie nawzajem, tworzy się zamknięty cykl. W takiej sytuacji licznik odwołań żadnego z obiektów nigdy nie spadnie do zera, co uniemożliwi zwolnienie pamięci i spowoduje wyciek pamięci (memory leak).
Czym jest std::weak_ptr?
Aby przerwać cykle własności, biblioteka standardowa oferuje std::weak_ptr. Jest to inteligentny wskaźnik, który obserwuje obiekt zarządzany przez shared_ptr, ale bez zwiększania licznika odwołań (reference count).
Nie posiada bezpośrednio zasobu, więc nie zapobiega jego zniszczeniu.
#include <memory>
std::shared_ptr<int> shared = std::make_shared<int>(42);
std::weak_ptr<int> weak = shared; // Non incrementa il contatore!
Weryfikacja i dostęp do zasobu
Ponieważ wskaźnik weak_ptr nie posiada zasobu na własność, może on zostać zwolniony w dowolnym momencie (gdy wszystkie powiązane wskaźniki shared_ptr opuszczą zakres).
Aby skorzystać z obserwowanego zasobu, musimy najpierw:
- Sprawdzić, czy jest nadal ważny, używając
expired(). - Tymczasowo przekonwertować
weak_ptrnashared_ptrza pomocą metodylock(). Jeśli zasób jest nadal aktywny,lock()zwraca prawidłowyshared_ptr, w przeciwnym razie zwraca wskaźnik pusty (nullptr).
if (!weak.expired()) {
// lock() crea uno shared_ptr temporaneo per garantire l'accesso sicuro
if (std::shared_ptr<int> sharedAccess = weak.lock()) {
std::cout << *sharedAccess << std::endl;
}
} else {
std::cout << "Risorsa deallocata!" << std::endl;
}
Spróbuj sam
Zadeklaruj std::weak_ptr<int> o nazwie wPtr zainicjalizowany na podstawie sPtr. Następnie wypisz wynik logiczny zwrócony przez wPtr.expired() za pomocą std::cout.
Pokaż wskazówkę
Zadeklaruj wskaźnik `weak_ptr` określając ten sam typ ogólny `<int>` i przypisz do niego bezpośrednio `sPtr`.
Rozwiązanie dostępne po 3 próbach
Użyj metody lock() na wPtr, aby uzyskać tymczasowy shared_ptr. Jeśli operacja powiedzie się (wskaźnik nie jest pusty), wypisz na ekranie wyłuskaną wartość.
Pokaż wskazówkę
Zainicjalizuj zmienną wewnątrz bloku `if` wywołując `wPtr.lock()`, a następnie wypisz zasób wyłuskując go za pomocą gwiazdki `*`.
Rozwiązanie dostępne po 3 próbach