Основы программирования

Операторы new и delete языка C++


В языке C++ для захвата и освобождения динамической памяти используются операторы new и delete. Они являются частью языка C++, в отличие от функций malloc и free, входящих в библиотеку стандартных функций Си.

Пусть T - некоторый тип языка Си или C++, p - указатель на объект типа T. Тогда для захвата памяти размером в один элемент типа T используется оператор new:

T *p; p = new T;

Например, для захвата восьми байтов под вещественное число типа double используется фрагмент

double *p; p = new double;

При использовании new, в отличие от malloc, не нужно приводить указатель от типа void* к нужному типу: оператор new возвращает указатель на тип, записанный после слова new. Сравните два эквивалентных фрагмента на Си и C++:

double *p; p = (double*) malloc(sizeof(double));

double *p; p = new double;

Конечно, второй фрагмент гораздо короче и нагляднее.

Оператор new удобен еще и тем, что можно присвоить начальное значение объекту, созданному в динамической памяти (т.е. выполнить инициализацию объекта). Для этого начальное значение записывается в круглых скобках после имени типа, следующего за словом new. Например, в приведенной ниже строке захватывается память под вещественное число, которому присваивается начальное значение 1.5:

double *p = new double(1.5);

Этот фрагмент эквивалентен фрагменту

double *p = new double; *p = 1.5;

С помощью оператора new можно захватывать память под массив элементов заданного типа. Для этого в квадратных скобках указывается длина захватываемого массива, которая может представляться любым целочисленным выражением. Например, в следующем фрагменте в динамической создается памяти для хранения вещественной матрицы размера m*n:

double *a; int m = 100, n = 101; a = new double[m * n];

Такую форму оператора new иногда называют векторной.

Оператор delete освобождает память, захваченную ранее с помощью оператора new, например,

double *p = new double(1.5); // Захват и инициализация . . . delete p; // Освобождение памяти

Если память под массив была захвачена с помощью векторной формы оператора new, то для ее освобождения следует использовать векторную форму оператора delete, в которой после слова delete записываются пустые квадратные скобки:


double *a = new double[100]; // Захватываем массив . . . delete[] a; // Освобождаем массив


  • Для массивов, состоящих из элементов базовых типов Си, при освобождении памяти можно использовать и обычную форму оператора delete. Единственное отличие векторной формы: при освобождении массива элементов класса, в котором определен деструктор, т.е. завершающее действие перед уничтожением объекта, этот деструктор вызывается для каждого элемента уничтожаемого массива. Поскольку для базовых типов деструкторы не определены, векторная и обычная формы оператора delete для них эквивалентны.


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

double *a = 0; // Нулевой указатель bool b; . . . if (b) { a = new double[1000]; . . . } . . . delete[] a;

Здесь в указатель a вначале записывается нулевой адрес. Затем, если справедливо некоторое условие, захватывается память под массив. Таким образом, при выполнении оператора delete указатель a содержит либо нулевое значение, либо адрес массива. В первом случае оператор delete ничего не делает, во втором освобождает память, занятую массивом. Такая технология применяется практически всеми программистами на C++: всегда инициализировать указатели на динамическую память нулевыми значениями и в результате не иметь никаких проблем при освобождении памяти.

Попытка освобождения нулевого указателя с помощью стандартной функции free может привести к аварийному завершению программы (это зависит от используемой Си-библиотеки: нормальная работа не гарантируется стандартом ANSI).


Содержание раздела