Умные указатели
Автоматическое и безопасное при исключениях владение объектами в куче
Главная идея: Умный указатель - это небольшой объект на стеке, который владеет выделенной в куче памятью и освобождает её автоматически в тот момент, когда владение заканчивается. Вместо того чтобы вручную сопоставлять каждому
new свой delete, вы позволяете деструктору указателя сделать это за вас. Это RAII (Resource Acquisition Is Initialization) применительно к памяти: время жизни ресурса привязано к времени жизни объекта на стеке.
К концу вы сможете:
- объяснить, почему сырые
new/deleteненадёжны, - использовать
std::unique_ptrдля монопольного владения и перемещать его, - использовать
std::shared_ptrдля совместного владения и читать его счётчик ссылок, - использовать
std::weak_ptr, чтобы наблюдать без владения и разрывать циклы ссылок.
1. Проблема сырых new / delete
Вы уже умеете выделять память в куче с помощью new и освобождать её через delete. Беда в том, что за delete отвечаете вы, и ошибиться можно многими способами:
- Утечка: вы забыли
delete, или раннийreturnпропустил его, и память так и не вернулась. - Висячий указатель: вы вызвали
deleteи продолжаете пользоваться указателем. - Двойное освобождение: две ветки кода вызывают
deleteдля одного объекта. - Утечка при исключении: исключение бросается между
newиdelete, поэтомуdeleteне выполняется.
void process() {
Widget* w = new Widget(); // ручное выделение
if (!w->load())
return; // БАГ: утечка w, delete не выполнится
w->run();
delete w; // легко забыть или пропустить из-за исключения
}
Умные указатели устраняют целый класс таких ошибок, перекладывая очистку на компилятор и деструктор. Поскольку умный указатель - это объект на стеке, его деструктор выполняется автоматически в конце области видимости, на любом пути выполнения, в том числе когда исключение разматывает стек.