В C++ управление памятью осуществляется с помощью явных операторов new и delete, которые выделяют и освобождают память динамически. Однако, при ручном управлении легко допустить утечку памяти или двойное удаление.
С появлением стандарта C++11 были введены умные указатели — такие как std::unique_ptr, std::shared_ptr, std::weak_ptr. Они автоматически управляют жизненным циклом объектов и гарантируют освобождение ресурсов при выходе за область видимости, даже в случае возникновения исключения.
Пример сравнения:
// Ручное освобождение памяти Foo* ptr = new Foo(); // ... delete ptr; // Более безопасно с умным указателем std::unique_ptr<Foo> ptr2 = std::make_unique<Foo>(); // delete не требуется — всё за вас сделает unique_ptr
Умные указатели уменьшают риск утечек памяти и делают код более безопасным и читаемым.
Что произойдет, если вызвать delete дважды для одного и того же указателя?
Ответ: После первого вызова delete память уже освобождена. Повторный вызов приведёт к неопределённому поведению (undefined behavior). Пример:
Foo* p = new Foo(); delete p; delete p; // ОШИБКА!
Во избежание этого устанавливайте указатель в nullptr после освобождения:
delete p; p = nullptr;
История
В крупном C++ проекте разработчик вручную освобождал динамическую память через
delete, забыв удалить указатель при выходе из нескольких веток функции с исключениями. Это привело к утечкам памяти, выявленным только при нагрузочном тестировании.
История
При попытке шарить сырые указатели между разными частями кода возникла двойная очистка памяти — одни из частей кода делала
delete, не уведомляя остальных. Итог: segfault в production, анализ core dump показал причину сразу.
История
После миграции старого проекта на новые стандарты C++ оставили часть кода с сырыми указателями, а новые классы работали уже со smart pointers. Столкнулись с ошибками передачи владения ресурсами: память освобождалась «дважды» — сначала вручную, потом автоматически десктрукторами умных указателей.