Динамическое выделение памяти в языке C++

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

Чтобы произвести увеличение массива во время выполнения программы необходимо выделить достаточный объем динамической памяти с помощью оператора new, перенести существующие элементы, а лишь затем добавить новые элементы. Управление динамической памятью полностью лежит на плечах программиста, поэтому после завершения работы с памятью необходимо самим возвратить память операционной системе с помощью оператора delete. Если память не возвратить операционной системе, то участок памяти станет недоступным для дальнейшего использования. Подобные ситуации приводят к утечке памяти.

Выделение памяти под один объект

Для выделения памяти под один объект предназначен следующий синтаксис:

<Указатель> = new <Тип данных>(<Начальное значение>);

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

int *p = new int;     // Без начального значения
int *p = new int(10); // С начальным значением

При выделении памяти может возникнуть ситуация нехватки памяти. В случае ошибки оператор new возбуждает исключение bad_alloc (класс исключения объявлен в файле new). Обработать это исключение можно с помощью конструкции try...catch. Пример выделения памяти с обработкой исключения:

#include <new>
// ... Фрагмент опущен ...
int *p = nullptr; // Создаем указатель
try {
   p = new int;   // Выделяем память
}
catch (std::bad_alloc &ex) {
   // Обработка исключения
}

Выделение памяти производится внутри блока try. Если при этом возникнет исключение bad_alloc, то управление будет передано в блок catch. После выполнения инструкций в блоке catch управление передается инструкции, расположенной сразу после блока. Иными словами, считается, что вы обработали исключение и можно продолжить выполнение программы. Следует учитывать, что пользоваться указателем после обработки нельзя, поэтому внутри блока catch обычно выводят сообщение об ошибке и завершают выполнение программы. Если исключение не обработать, то программа аварийно завершится. Если исключение не возникло, то инструкции внутри блока catch не выполняются.

Обратите внимание на то, что объявление указателя производится вне блока try. Если объявление разместить внутри блока, то область видимости переменной будет ограничена этим блоком. После выхода из блока переменная автоматически уничтожается, а выделенная память операционной системе не возвращается. Поэтому, объявление указателя должно находиться перед блоком, а не внутри него.

Возвратить ранее выделенную память операционной системе позволяет оператор delete. Оператор имеет следующий формат:

delete <Указатель>;

После использования оператора delete указатель по-прежнему будет содержать прежний адрес. Поэтому после использования оператора delete указатель принято обнулять. Пример выделения памяти под один объект приведен в листинге 3.14.

Листинг 3.14. Динамическое выделение памяти под один объект

#include <iostream>
#include <new>
#include <clocale>
#include <process.h>

int main() {
   std::setlocale(LC_ALL, "Russian_Russia.1251");
   int *p = nullptr;             // Создаем указатель
   try {
      p = new int;               // Выделяем память
   }
   catch (std::bad_alloc &ex) {
      std::cerr << "Не удалось выделить память" << std::endl;
      exit(1);                   // Выходим при ошибке
   }
   *p = 20;                      // Пользуемся памятью
   std::cout << *p << std::endl; // 20
   delete p;                     // Освобождаем память
   p = nullptr;                  // Обнуляем указатель
   return 0;
}

Учебник C++ (MinGW-W64)
Учебник C++ (MinGW-W64) в формате PDF

Помощь сайту

ЮMoney (Yandex-деньги): 410011140483022

ПАО Сбербанк:
Счет: 40817810855006152256
Реквизиты банка:
Наименование: СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК
Корреспондентский счет: 30101810500000000653
БИК: 044030653
КПП: 784243001
ОКПО: 09171401
ОКОНХ: 96130
Скриншот реквизитов