W C++ zarządzanie pamięcią odbywa się za pomocą jawnych operatorów new i delete, które dynamicznie alokują i zwalniają pamięć. Jednak przy ręcznym zarządzaniu łatwo popełnić błąd, prowadzący do wycieków pamięci lub podwójnego zwalniania.
Z pojawieniem się standardu C++11 wprowadzono inteligentne wskaźniki — takie jak std::unique_ptr, std::shared_ptr, std::weak_ptr. Automatycznie zarządzają cyklem życia obiektów i gwarantują zwolnienie zasobów po wyjściu z zakresu widoczności, nawet w przypadku wystąpienia wyjątku.
Przykład porównania:
// Ręczne zwalnianie pamięci Foo* ptr = new Foo(); // ... delete ptr; // Bezpieczniej z inteligentnym wskaźnikiem std::unique_ptr<Foo> ptr2 = std::make_unique<Foo>(); // delete nie jest wymagane — wszystko zrobi za Ciebie unique_ptr
Inteligentne wskaźniki zmniejszają ryzyko wycieków pamięci i czynią kod bardziej bezpiecznym i czytelnym.
Co się stanie, jeśli wywołasz delete dwa razy dla tego samego wskaźnika?
Odpowiedź: Po pierwszym wywołaniu delete pamięć już została zwolniona. Powtórne wywołanie doprowadzi do nieokreślonego zachowania (undefined behavior). Przykład:
Foo* p = new Foo(); delete p; delete p; // BŁĄD!
Aby tego uniknąć, ustaw wskaźnik na nullptr po zwolnieniu:
delete p; p = nullptr;
Historia
W dużym projekcie C++ programista ręcznie zwalniał dynamiczną pamięć za pomocą
delete, zapominając o usunięciu wskaźnika przy wyjściu z kilku gałęzi funkcji z wyjątkami. Doprowadziło to do wycieków pamięci, które ujawniły się dopiero podczas testów obciążeniowych.
Historia
Próba udostępnienia surowych wskaźników między różnymi częściami kodu spowodowała podwójne zwalnianie pamięci — jedna część kodu wykonywała
delete, nie informując innych. Efekt: segfault w produkcji, analiza zrzutu pamięci pokazuje przyczynę od razu.
Historia
Po migracji starego projektu do nowych standardów C++ pozostawiono część kodu z surowymi wskaźnikami, podczas gdy nowe klasy działały już z inteligentnymi wskaźnikami. Napotkano błędy w przekazywaniu własności zasobów: pamięć była zwalniana „dwa razy” — najpierw ręcznie, potem automatycznie przez destruktory wskaźników inteligentnych.