Этот сайт использует cookies. Продолжение работы с сайтом означает, что Вы согласны!
«Умные» указатели
Классы могут быть очень большими или экземпляров класса может быть очень много, в результате мы вынуждены создавать объекты в динамической памяти, т. к. размер стека ограничен. В разд. 13.14 мы уже рассматривали способы динамического создания объектов с помощью оператора new
. В этом разделе мы рассмотрим проблемы при работе с динамическими объектами, а также научимся эти проблемы решать.
A
и B
из листинга 13.19.Итак, давайте создадим объект класса B
внутри блока:
{
B *pB = new B(20);
// Выполняем операции
std::cout << pB->y << std::endl; // 20
}
// Здесь указатель pB уже не существует
// Утечка памяти!!!
Указатель pB
создан внутри блока (области, ограниченной фигурными скобками), следовательно, он является локальной переменной, область видимости которой ограничена блоком. После блока указатель pB
уже не существует. В результате память под указатель будет освобождена, а вот динамическая память автоматически освобождена не будет и мы получим утечку памяти. Заметьте, что деструктор объекта не вызывается. Попробуйте вместо блока использовать бесконечный цикл while
и понаблюдайте за размером памяти в Диспетчере задач Windows. Так вы очень быстро поймете, к чему может привести утечка памяти.
Чтобы избежать утечки памяти нужно динамическую память освобождать явным образом. Как вы уже знаете, для освобождения динамической памяти предназначен оператор delete
. Давайте переделаем предыдущий пример и исправим ошибку:
{
B *pB = new B(20);
// Выполняем операции
std::cout << pB->y << std::endl; // 20
// Освобождаем динамическую память
delete pB;
}
// Здесь указатель pB уже не существует
// Все равно возможна утечка памяти!!!
Итак, указатель после выхода из блока удаляется, динамическая память освобождается и вызывается деструктор. Вроде все хорошо, но это не так! Проблема заключается в том, что при выполнении операций с объектом может произойти ошибка, которая сгенерирует исключение. В результате поток управления не дойдет до оператора delete
, динамическая память освобождена не будет и деструктор вызван не будет. В результате опять получаем утечку памяти:
try {
B *pB = new B(20);
// Выполняем операции
throw std::exception(); // Генерация исключения
std::cout << pB->y << std::endl;
// Освобождаем динамическую память
delete pB;
} catch (std::exception &ex) {
std::cout << "Исключение обработано" << std::endl;
}
// Утечка памяти!!!
Результат (заметьте, что деструктор вызван не был):
B::B()
Исключение обработано
Для решения проблем с освобождением динамической памяти предназначены классы unique_ptr
, shared_ptr
и weak_ptr
, которые называются «умными» указателями. Прежде чем использовать классы не забудьте подключить заголовочный файл memory
:
#include <memory>
Помощь сайту
ЮMoney (Yandex-деньги): 410011140483022
ПАО Сбербанк:
Счет: 40817810855006152256
Реквизиты банка:
Наименование: СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК
Корреспондентский счет: 30101810500000000653
БИК: 044030653
КПП: 784243001
ОКПО: 09171401
ОКОНХ: 96130
Скриншот реквизитов