Резервирование и освобождение памяти (операторы new и delete)

Основное назначение указателей состоит в обеспечении возможности работы с динамическими (создаваемыми в процессе выполнения программы) переменными встроенных и производных типов. При такой работе указатели используются как средство хранения адресов резервируемых и освобождаемых участков памяти. Сами же действия, связанные с резервированием и освобождением памяти, осуществляют операторы new и delete.

Оператор new резервирует в области динамической памяти запрошенный участок памяти и возвращает его адрес, а оператор delete освобождает зарезервированный ранее участок памяти. Возможный формат этих операторов:

идентификатор = new тип ;

delete идентификатор ;

Здесь идентификатор – имя указателя, получающего в качестве значения адрес выделенной памяти, достаточной для размещения данных указанного типа. Пример:

int *ip; // указатель на целое значение типа int

...

ip = new int; // резервирование памяти для целого числа

...

delete ip; // освобождение памяти, адресуемой указателем ip

После выполнения последнего оператора примера память, выделенная для переменной типа int и адресуемая указателем ip, становится свободной (недоступной для использования, но доступной для нового резервирования оператором new). Переменная-указатель ip по-прежнему может использоваться в программе, но в текущий момент времени его значение становится неопределенным, указывающим на недоступный участок памяти.

Объявление указателя и резервирование памяти можно объединить:

int *ip = new int; // объявление и инициализация указателя на целое число

Приведенное объявление инициализирует переменную-указатель ip адресом выделенного ей участка памяти для переменной типа int, при этом значение данного участка памяти не определено. Существует возможность применения оператора new с инициализацией выделяемого участка памяти соответствующим значением. Формат оператора new при такой инициализации:

идентификатор = new тип ( значение );

например:

int *ip = new int(10); // выделение участка памяти для целого числа

// и его инициализация значением 10

Последний оператор объявляет переменную-указатель ip, резервирует требуемый участок памяти, присваивает этот адрес объявленной переменной и записывает по данному адресу начальное значение 10.

Для резервирования памяти для одномерного массива следует использовать оператор new формата

идентификатор = new тип [ размер ]

а для его освобождения – оператор delete формата

delete [] идентификатор ;

например:

int *p = new int[5]; // выделение памяти для массива из пяти целых чисел

...

delete []p; // освобождение памяти, зарезервированной для массива p

Наличие квадратных скобок указывает на необходимость освобождения памяти, занимаемой массивом, а не одной переменной.

Размер участка памяти, выделяемой для одномерного массива, может задаваться как целочисленным константным выражением, так и выражением, содержащим переменные, например:

int n;

...

cin >> n;

int *p = new int[n]; // выделение памяти для массива из n целых чисел

Инициализация элементов массива, определяемого посредством оператора new, в C++ не предусмотрена.

Не следует забывать о различиях в использовании квадратных и круглых скобок при работе с динамической памятью. Так, оператор:

int *p = new int[n];

осуществляет выделение памяти для массива из n целых чисел, а похожий оператор

int *p = new int(n);

– выделение памяти для одной переменной целого типа с начальным значением n.

С помощью оператора newможно выделять память и для многомерных (в частности, двумерных) массивов и массивов указателей.

Для освобождения памяти, динамически (с помощью оператора new) выделенной под двумерный массив a, следует использовать тот же, что и для одномерного массива, оператор

delete []a;

Поскольку при создании динамических массивов всего одна размерность может быть переменной, использование динамических двумерных массивов целесообразно, когда их необходимость заранее неизвестна и зависит от каких-то внешних условий.

Следует подчеркнуть, что динамически (с помощью оператора delete) можно освободить только ту память, которая была динамически (с помощью оператора new) получена.