Historia kwestii:
Zwykłe (surowe) wskaźniki to tradycyjny mechanizm w C++ do pracy z pamięcią dynamiczną. To uniwersalny mechanizm abstrakcyjny, ale niestety bardzo podatny na błędy: wycieki pamięci, podwójne usuwanie, błędy Dangling pointer. Dlatego od C++11 standardowa biblioteka zawiera wskaźniki inteligentne — klasy szablonowe (std::unique_ptr, std::shared_ptr, std::weak_ptr), które automatycznie zarządzają czasem życia obiektu.
Problem:
Podczas korzystania z zwykłych wskaźników odpowiedzialność za alokowanie i zwalnianie pamięci spoczywa na programiście. Błędy w zwalnianiu pamięci prowadzą do wycieków (memory leaks), uszkodzenia danych, awarii programu. Szczególnie trudne przypadki występują w obsłudze wyjątków lub przy przekazywaniu wskaźników do innych funkcji.
Rozwiązanie:
Wskaźniki inteligentne enkapsulują zaalokowaną pamięć i automatycznie ją zwalniają, gdy nie ma więcej właścicieli. Realizują RAII. std::unique_ptr zapewnia wyłączne posiadanie, std::shared_ptr — dzielone, std::weak_ptr — niekontrolujące (w celu zapobiegania "cyklom odniesień").
Przykład kodu:
#include <memory> void foo() { std::unique_ptr<int> p = std::make_unique<int>(5); // pamięć zostanie zwolniona nawet w przypadku wyjątku // ... }
Kluczowe cechy:
Czy można użyć std::unique_ptr w tablicy utworzonej za pomocą new[]?
Nie, dla tablic użyj std::unique_ptr<T[]>: wtedy zostanie wywołany delete[] zamiast delete.
std::unique_ptr<int[]> arr(new int[10]);
Czy standardowe wskaźniki inteligentne mogą zapobiec wszystkim możliwym wyciekom pamięci?
Nie. Na przykład, cykliczne odniesienia między std::shared_ptr prowadzą do wycieków. Aby przerwać takie cykle, użyj std::weak_ptr.
Czy wskaźniki inteligentne mogą "usunąć" ten sam obiekt dwa razy?
Nie, jeśli nie naruszasz logiki posiadania (nie używaj surowych wskaźników!). Jeśli ręcznie kopiujesz surowy wskaźnik, zniszczenie może nastąpić dwa razy.
Używane są surowe wskaźniki, pamięć zwalniana jest ręcznie, przy wyrzuceniu wyjątku pamięć nie jest zwalniana.
Zalety:
Wady:
Używane jest std::unique_ptr i std::make_unique do tworzenia obiektów i przekazywania ich do funkcji.
Zalety:
Wady: