В ответах есть несколько слоев.
Во-первых, переменные могут быть объявлены несколькими различными способами:
- В качестве локальных переменных (либо внутри функции, либо в качестве членов класса). Примеры:
int i
или int i = 42
. Они имеют автоматическую продолжительность хранения (эти примеры технически сокращены для auto int i
или auto int i = 42
, хотя ключевое слово auto
практически никогда не используется. Это означает, что эти переменные будут автоматически освобождены, когда они выйдут из области видимости. Их деструктор гарантированно будет вызван (независимо от того, как вы выходите из области, будь то из функции, возвращаемой функцией или с помощью исключения, их деструктор будет вызываться, когда они выходят из области действия, а затем используемая ими память освобождается) . Локальные переменные, объявленные так, расположены в стеке.
- Статические переменные (с ключевым словом
static
, подразумевающими статическую длительность хранения, в отличие от автоматического, показанного выше. Они просто остаются на время действия программы, поэтому их не нужно освобождать
- в куче, с динамическим распределением (
new int
или new int(42)
). Их нужно освободить вручную, позвонив по номеру delete
.
Так что на самом низком уровне вам просто нужно сохранить симметрию. Если что-то было выделено с new
, освободите его с помощью delete,
malloc is freed by
free , and
new [] by
delete [] `. И переменные, которые объявлены без каких-либо из них, автоматически обрабатываются и не должны освобождаться вручную.
Теперь для простоты управления памятью обычно используется RAII . Техника основана на наблюдении, что только динамически распределяемые объекты должны быть освобождены вручную, и что локальные переменные дают вам очень удобный крючок для реализации пользовательских действий, когда локальная переменная выходит из области видимости.
Таким образом, динамическое размещение заключено в отдельный класс, который может быть выделен как локальный объект в стеке. Затем он может в своем конструкторе создавать любые динамические выделения, которые вам нужны, а его деструктор очищает его с помощью необходимых вызовов delete
.
Это означает, что вам, по сути, никогда не придется звонить delete
в коде верхнего уровня. Он практически всегда будет скрыт за деструктором объекта RAII. new
вызовы также становятся редкими, но все еще используются вместе с интеллектуальными указателями (такими как: boost::shared_ptr<int>(new int(42))
, который динамически выделяет целое число, а затем передает его интеллектуальному указателю, который берет на себя владение им и очищает его автоматически .