Умные указатели. Smart pointers.
В языке C++ одной из главных проблем являются утечки памяти, для упрощения работы с ними используются умные указатели.
По сути умный указатель – шаблонный класс в конструкторе которого «захватывается» указатель на область в динамической памяти, а в деструкторе область освобождается.
В чем смысл? Как известно деструктор вызывается при выходе из зоны видимости функции/программы и тд., т.е. в момент вызова деструктора мы уже знаем что не будем работать с этим классом, а т.к. в деструкторе есть оператор delete или delete[], то мы освобождаем память.
Главная проблема умных указателей – работа со ссылками на одну и тоже область в памяти (т.к. вызовется деструктор на одну и туже область в памяти и будет ошибка), для борьбы с подобным используются умные указатели из библиотеки <memory>
В C++ есть стандартная библиотека для деструкторов
#include <memory>
Внутри есть несколько видов умных указателей:
auto_ptr:
При присвоении двум указателям ссылки на один объект в памяти например:
auto_ptr<int> autoPtr_1(new int(10));
auto_ptr<int> autoPtr_2(autoPtr_1);
ссылку будет иметь лишь последний автоматический указатель, а все предыдущиебудут иметь null/nullptr
unique_ptr:
При присвоении двум указателям ссылки на один объект в памяти например:
unique_ptr<int> uniqPtr_1(new int(10));
unique_ptr<int> uniqPtr_2;
unique запрещает прямое присвоение другого умного указателя, для присвоения 2-м указателям ссылки на одим объект используется
uniqPtr_2=move(uniqPtr_1);
или
uniqPtr_2.swap(uniqPtr_1);
В обоих случаях ссылку будет иметь лишь последний уникальный указатель.
Данный тип указателя также имеет методы:
uniqPtr_1.reset(); //удалить указатель и данные
uniqPtr_1.release(); //удалить только указатель
shared_ptr (общий указатель):
Данный тип указателя используется наиболее часто, главная идея – сохранять данные о числе экземпляров умного указателя и удалять данные только когда число указателей на данную область памяти равно 0.
т.е. при создании
shared_ptr<int> sharedPtr_1(new int(10));
shared_ptr<int> sharedPtr_2(uniqPtr_1);
Умный указатель будет знать, что на переменную со значением “10” ссылаются 2 умных указателя, при вызове деструкторов счетчик будет уменьшаться, если счетчик дойдет до 0, то вызовется оператор delete или delete[].
Указатель на динамический массив:
чтобы сделать указатель на динамический массив в скобки шаблона <> надо поставить тип и скобки, например:
shared_ptr<int[]>sharedPtr(new int[2]{1,2});