Świat, w którym żyje Bjarne, jest bardzo ... akademicki, z braku lepszego określenia. Jeśli kod można zaprojektować i ustrukturyzować w taki sposób, że obiekty mają bardzo przemyślane hierarchie relacyjne, tak że relacje własności są sztywne i nieugięte, kod przepływa w jednym kierunku (od wysokiego poziomu do niskiego poziomu), a obiekty rozmawiają tylko z tymi niższymi hierarchii, wtedy nie będzie wiele potrzeby shared_ptr
. Jest to coś, czego używasz w tych rzadkich przypadkach, gdy ktoś musi złamać zasady. Ale w przeciwnym razie możesz po prostu wsadzić wszystko w vector
s lub inne struktury danych, które używają semantyki wartości, i unique_ptr
s dla rzeczy, które musisz przydzielić pojedynczo.
Chociaż jest to świetny świat do życia, to nie jest to, co możesz robić przez cały czas. Jeśli nie możesz zorganizować swojego kodu w ten sposób, ponieważ konstrukcja systemu, który próbujesz stworzyć, oznacza, że jest to niemożliwe (lub po prostu głęboko nieprzyjemne), będziesz potrzebować wspólnej własności obiektów coraz bardziej .
W takim systemie trzymanie nagich wskazówek nie jest ... dokładnie niebezpieczne, ale rodzi pytania. Wspaniałą rzeczą shared_ptr
jest to, że zapewnia rozsądne składniowe gwarancje dotyczące żywotności obiektu. Czy można to zepsuć? Oczywiście. Ale ludzie mogą także const_cast
rzeczy; podstawowa opieka i karmienie shared_ptr
powinny zapewniać rozsądną jakość życia przydzielonym obiektom, których własność musi być dzielona.
Są też weak_ptr
s, których nie można użyć przy braku a shared_ptr
. Jeśli twój system ma sztywną strukturę, możesz zapisać nagi wskaźnik do jakiegoś obiektu, wiedząc, że struktura aplikacji zapewnia, że wskazany obiekt przeżyje cię. Możesz wywołać funkcję, która zwraca wskaźnik do jakiejś wartości wewnętrznej lub zewnętrznej (na przykład znajdź obiekt o nazwie X). We właściwie skonstruowanym kodzie funkcja ta byłaby dostępna tylko wtedy, gdy gwarantowano by, że czas życia obiektu przekroczy twój; w ten sposób przechowywanie nagiego wskaźnika w obiekcie jest w porządku.
Ponieważ tej sztywności nie zawsze można osiągnąć w rzeczywistych systemach, potrzebujesz sposobu, aby zapewnić rozsądną trwałość. Czasami nie potrzebujesz pełnej własności; Czasami musisz po prostu wiedzieć, kiedy wskaźnik jest zły lub dobry. Tam właśnie weak_ptr
przychodzi. Były przypadki, w których mogłem użyć unique_ptr
lub boost::scoped_ptr
, ale musiałem użyć, shared_ptr
ponieważ szczególnie potrzebowałem dać komuś „niestabilny” wskaźnik. Wskaźnik, którego życie było nieokreślone, mogli zapytać, kiedy wskaźnik ten zostanie zniszczony.
Bezpieczny sposób na przetrwanie, gdy stan świata jest nieokreślony.
Czy można to zrobić za pomocą jakiegoś wywołania funkcji, aby uzyskać wskaźnik, zamiast przez weak_ptr
? Tak, ale to może być łatwiejsze do złamania. Funkcja, która zwraca nagi wskaźnik, nie ma możliwości syntaktycznego sugerowania, że użytkownik nie robi czegoś takiego jak przechowywanie tego wskaźnika w dłuższej perspektywie. Zwrócenie a shared_ptr
także sprawia, że zbyt łatwo jest go po prostu przechowywać i potencjalnie przedłużyć żywotność obiektu. Zwrócenie weak_ptr
jednak zdecydowanie sugeruje, że przechowywanie tego, shared_ptr
co otrzymujesz, lock
jest ... wątpliwym pomysłem. Nie powstrzyma cię to przed zrobieniem tego, ale nic w C ++ nie powstrzyma cię przed złamaniem kodu. weak_ptr
zapewnia minimalny opór przed robieniem rzeczy naturalnych.
To nie znaczy, że shared_ptr
nie można tego nadużywać ; z pewnością może. Szczególnie wcześniej- unique_ptr
było wiele przypadków, w których właśnie użyłem, boost::shared_ptr
ponieważ musiałem przekazać wskaźnik RAII lub umieścić go na liście. Bez przemieszczania się i semantyki unique_ptr
, boost::shared_ptr
był jedynym realnym rozwiązaniem.
I możesz go używać w miejscach, w których jest to zupełnie niepotrzebne. Jak wspomniano powyżej, odpowiednia struktura kodu może wyeliminować potrzebę niektórych zastosowań shared_ptr
. Ale jeśli twój system nie może być skonstruowany jako taki i nadal robi to, co musi, shared_ptr
będzie bardzo przydatny.