Вариант 1 .
Самый простой способ - полностью избежать new
и delete
.
Вместо:
b = new int;
b = new int;
delete b;
Запись:
std::unique_ptr<int> b;
...
b = std::make_unique<int>();
b = std::make_unique<int>();
Когда b
перезаписывается или выходит из области видимости, это освобождает память. Нет delete
требуется или даже разрешено. Обратите внимание, что это похоже на сборщик мусора Java, но в большинстве случаев достаточно хорошо.
Вариант 2.
Другой способ - использовать дополнительный сборщик мусора , но это решение не рекомендуется. Во-первых, сборщик мусора является консервативным, то есть существует вероятность утечки памяти, несмотря на сборщик мусора. Во-вторых, эти решения имеют тенденцию усугублять существующие проблемы, поскольку утечки памяти не будут замечены и устранены при появлении. Лечение утечек памяти через год после введения на несколько порядков сложнее, чем лечение через час после введения.
ПРИМЕЧАНИЕ : Использование unique_ptr
не так безопасно, как в языках с сборкой мусора, таких как C #, Java и Python. Он терпит неудачу, когда нет четкой модели владения и когда существует круговое владение. Если элемент a
имеет от unique_ptr
до b
, а b
имеет от unique_ptr
до a
, то они никогда не будут освобождены. Они никогда не будут освобождены, поскольку unique_ptr
освобождает объект в деструкторе, но никто не будет вызывать деструктор ни a
, ни b
. Если никто не вызывает деструктор, то unique_ptr
никогда не удалит объект и никогда не вызовет деструктор другого объекта.
ПРИМЕЧАНИЕ 2 : Иногда вместо unique_ptr
следует использовать std::shared_ptr
, но это не решает проблему циклических ссылок. Это только решает проблему нескольких владельцев одного объекта.
ПРИМЕЧАНИЕ 3 : эти интеллектуальные указатели не снижают вероятность переполнения стека из-за глубокой рекурсии в деструкторах. Это может произойти при рекурсивном уничтожении длинных связанных списков или в несбалансированных бинарных деревьях. Использование unique_ptr
для этого случая просто скрывает тот факт, что рекурсия имеет место.