Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Либерти Джесс. Освой самостоятельно С++ за 21 день. - royallib.ru.rtf
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
2.55 Mб
Скачать

Оператор new

Для выделения памяти в области динамического распределения используется ключевое слово new. После new следует указать тип объекта, который будет размещаться в памяти. Это необходимо для определения размера области памяти, требуемой для хранения объекта. Написав, например, new unsigned short int, мы выделим два байта памяти, а строка new long динамически выделит четыре байта.

В качестве результата оператор new возвращает адрес выделенного фрагмента памяти. Этот адрес должен присваиваться указателю. Например, для выделения памяти в области динамического обмена переменной типа unsigned short можно использовать такую запись:

unsigned short int * pPointer; pPointer = new unsigned short int;

Или выполнить те же действия, но в одной сороке:

unsigned short int * pPointer = new unsigned short int;

В каждом случае указатель pPointer будет указывать на ячейку памяти в области динамического обмена, содержащую значение типа unsigned short. Теперь pPointer можно использовать как любой другой указатель на переменную этого типа. Чтобы занести в выделенную область памяти какое-нибудь значение, напишите такую строку:

*pPointer = 72;

Эта строка означает следующее: "записать число 72 в память по адресу, хранящемуся в pPointer".

Ввиду того что память является ограниченным ресурсом, попытка выделения памяти оператором new может оказаться неудачной. В этом случае возникнет исключительная ситуация, которая рассматривается на занятии 20.

Оператор delete

Когда память, выделенная под переменную, больше не нужна, ее следует освободить. Делается это с помощью оператора delete, после которого записывается имя указателя. Оператор delete освобождает область памяти, определенную указателем. Необходимо помнить, что указатель, в отличие от области памяти, на которую он указывает, является локальной переменной. Поэтому после выхода из функции, в которой он был объявлен, этот указатель станет недоступным. Однако область памяти, выделенная оператором new, на которую сослался указатель, при этом не освобождается. В результате часть памяти окажется недоступной. Программисты называют такую ситуацию утечкой памяти. Такое название полностью соответствует действительности, поскольку до завершения работы программы эту память использовать нельзя, она как бы "вытекает" из вашего компьютера.

Чтобы освободить выделенную память, используйте ключевое слово delete, например:

delete pPointer;

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

Предупреждение: Когда оператор delete применяется к указателю, происходит освобождение области динамической памяти, на которую этот указатель ссылается. Повторное применение оператора delete к этому же указателю приведет к зависанию программы. Рекомендуется при освобождении области динамической памяти присваивать связанному с ней указателю нулевое значение. Вызов оператора delete для нулевого указателя пройдет совершенно безболезненно для программы, например:

Animal *pDog = new Animal;

delete pDog; // освобождение динамической памяти

pDog = 0 // присвоение указателю нулевого значения

              // ...

delete pDog; // бессмысленная, но совершенно безвредная строка

Листинг 8.4. Выделение, использование и освобождение динамической памяти

1; // Листинг 8, 4,

2; // Выделение, использование и освобождение динамической памяти 3;

4: #include <iostream.h>

5: int main()

6: {

7:    int localVariable = 5;

8:    int * pLocal= &localVariable;

9:    int * pHeap = new int;

10:   рНеар = 7;

11:   cout << "localVariable: " << localVariable << "\n";

12:   cout << "*pLocal: " << *pLocal << "\n";

13:   cout << "*pHeap; " << *pHeap << "\n";

14:   delete рНеар;

15:   рНеар = new int;

16:   *pHeap = 9;

17:   cout << "*pHeap: " << *pHeap << "\n";

18:   delete рНеар;

19:   return 0;

20: }

Результат:

localVariable: 5

*pLocal: 5

*pHeap: 7

*pHeap: 9

Анализ: В строке 7 объявляется и инициализируется локальная переменная localVariable. Затем объявляется указатель, которому присваивается адрес этой переменной (строка 8). В строке 9 выделяется память для переменной типа int и адрес выделенной области помещается в указатель рНеар. Записав по адресу, содержащемуся в рНеар, значение 7, можно удостовериться в том, что память была выделена корректно (строка 10). Если бы память под переменную не была выделена, то при выполнении этой строки появилось бы сообщение об ошибке.

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

В строке 10, после выделения памяти, по адресу в указателе записывается значение 7. Затем в строках 11 и 12 значения локальной переменной и указателя pLocal выводятся на экран. Вполне понятно, почему эти значения равны. Далее, в строке 13, выводится значение, записанное по адресу, хранящемуся в указателе рНеар. Таким образом, подтверждается, что значение, присвоенное в строке 10, действительно доступно для использования.

Освобождение области динамической памяти, выделенной в строке 9, осуществляется оператором delete в строке 14. Освобожденная память становится доступной для дальнейшего использования, и ее связь с указателем разрывается. После этого указатель рНеар может использоваться для хранения нового адреса. В строках 15 и 16 выполняется повторное выделение памяти и запись значения по соответствующему адресу. Затем в строке 17 это значение выводится на экран, после чего память освобождается.

Вообще говоря, строка 18 не является обязательной, так как после завершения работы программы вся выделенная в ней память автоматически освобождается. Однако явное освобождение памяти считается как бы правилом хорошего тона в программировании. Кроме того, это может оказаться полезным при редактировании программы.