Динамическое выделение памяти в языке C++
Как вы уже знаете, при объявлении переменной необходимо указать тип данных, а для массива дополнительно задать точное количество элементов. На основе этой информации при запуске программы автоматически выделяется необходимый объем памяти. После завершения программы память автоматически освобождается. Иными словами, объем памяти необходимо знать до выполнения программы. Во время выполнения программы создать новую переменную или увеличить размер существующего массива нельзя.
Чтобы произвести увеличение массива во время выполнения программы необходимо выделить достаточный объем динамической памяти с помощью оператора new , перенести существующие элементы, а лишь затем добавить новые элементы. Управление динамической памятью полностью лежит на плечах программиста, поэтому после завершения работы с памятью необходимо самим возвратить память операционной системе с помощью оператора delete . Если память не возвратить операционной системе, то участок памяти станет недоступным для дальнейшего использования. Подобные ситуации приводят к утечке памяти.
Выделение памяти под один объект
Для выделения памяти под один объект предназначен следующий синтаксис:
Оператор new выделяет объем памяти, необходимый для хранения значения указанного типа, записывает в эту память начальное значение (если оно задано) и возвращает адрес. Работать в дальнейшем с этим участком памяти можно с помощью указателя. Пример выделения памяти:
При выделении памяти может возникнуть ситуация нехватки памяти. В случае ошибки оператор new возбуждает исключение bad_alloc (класс исключения объявлен в файле new ). Обработать это исключение можно с помощью конструкции try. catch . Пример выделения памяти с обработкой исключения:
Выделение памяти производится внутри блока try . Если при этом возникнет исключение bad_alloc , то управление будет передано в блок catch . После выполнения инструкций в блоке catch управление передается инструкции, расположенной сразу после блока. Иными словами, считается, что вы обработали исключение и можно продолжить выполнение программы. Следует учитывать, что пользоваться указателем после обработки нельзя, поэтому внутри блока catch обычно выводят сообщение об ошибке и завершают выполнение программы. Если исключение не обработать, то программа аварийно завершится. Если исключение не возникло, то инструкции внутри блока catch не выполняются.
Обратите внимание на то, что объявление указателя производится вне блока try . Если объявление разместить внутри блока, то область видимости переменной будет ограничена этим блоком. После выхода из блока переменная автоматически уничтожается, а выделенная память операционной системе не возвращается. Поэтому, объявление указателя должно находиться перед блоком, а не внутри него.
Возвратить ранее выделенную память операционной системе позволяет оператор delete . Оператор имеет следующий формат:
После использования оператора delete указатель по-прежнему будет содержать прежний адрес. Поэтому после использования оператора delete указатель принято обнулять. Пример выделения памяти под один объект приведен в листинге 3.14.
Листинг 3.14. Динамическое выделение памяти под один объект
Выделение памяти под массив
Выделение памяти под массив производится следующим образом:
Освободить выделенную память можно так:
Обратите внимание на то, что при освобождении памяти количество элементов не указывается. Пример выделения памяти под массив приведен в листинге 3.15.
Листинг 3.15. Динамическое выделение памяти под массив
Выделение памяти без возбуждения исключения
В ранних версиях C++ при нехватке памяти возвращался нулевой указатель. Такая же ситуация возникает в языке C при использовании функции malloc() . Чтобы оператор new , возвращал нулевой указатель, а не возбуждал исключение используется следующий синтаксис:
Для использования nothrow требуется подключить файл new . После выделения памяти следует проверить указатель на отсутствие нулевого значения. Пример выделения памяти без возбуждения исключения приведен в листинге 3.16.
Листинг 3.16. Динамическое выделение памяти без возбуждения исключения
Динамическое выделение памяти в языке C
Язык C++ поддерживает также функции malloc() , calloc() , realloc() и free() , позволяющие управлять динамической памятью в языке C. Хотя эти функции можно использовать и в языке C++, тем не менее стоит отдать предпочтение оператору new и явной обработке исключения. Описание этих функций приведено в книге лишь для того, чтобы вы могли разобраться в чужом коде.
Функции malloc() и free()
Для выделения динамической памяти в языке C предназначена функция malloc() . Прототип функции:
Функция malloc() принимает в качестве параметра размер памяти в байтах и возвращает указатель, имеющий тип void * . Если память выделить не удалось, то функция возвращает нулевой указатель. Все элементы будут иметь произвольное значение, так называемый «мусор». В языке C указатель типа void * неявно приводится к другому типу, поэтому использовать явное приведение не нужно. В языке C++ перед присвоением значения указателю необходимо выполнить явное приведение к используемому типу. Кроме того, чтобы программа была машинонезависимой следует применять оператор sizeof для вычисления размера памяти, требуемого для определенного типа.
Освободить ранее выделенную динамическую память позволяет функция free() . Функция принимает в качестве параметра указатель на ранее выделенную память и освобождает ее. Прототип функции:
Пример выделения памяти для одного объекта приведен в листинге 3.17.
Листинг 3.17. Динамическое выделение памяти для одного объекта
Пример выделения памяти под массив приведен в листинге 3.18.
Листинг 3.18. Динамическое выделение памяти под массив
Функция calloc()
Вместо функции malloc() можно воспользоваться функцией calloc() . Прототип функции:
В первом параметре функция calloc() принимает количество элементов, а во втором — размер одного элемента. Если память выделить не удалось, то функция возвращает нулевой указатель. Все элементы будут иметь значение 0 .
Используя функцию calloc() , следующую инструкцию из листинга 3.18:
мы можем записать так:
В качестве примера использования функции calloc() создадим двумерный массив (листинг 3.19). Для этого нам нужно создать массив указателей и в каждом элементе массива сохранить адрес строки. Память для каждой строки нужно выделить дополнительно.
Листинг 3.19. Динамическое выделение памяти под двумерный массив
Обратите внимание: при возвращении памяти вначале освобождается память, выделенная ранее под строки, а лишь затем освобождается память, выделенная ранее под массив указателей.
Так как мы сохраняем в массиве указателей лишь адрес строки, а не саму строку, количество элементов в строке может быть произвольным. Это обстоятельство позволяет создавать так называемые «зубчатые» двумерные массивы.
Строки в памяти могут быть расположены в разных местах, что не позволяет эффективно получать доступ к элементам двумерного массива. Чтобы доступ к элементам сделать максимально быстрым, можно представить двумерный массив в виде одномерного массива (листинг 3.20).
Листинг 3.20. Представление двумерного массива в виде одномерного
Так как в этом случае все элементы двумерного массива расположены в смежных ячейках, мы можем получить доступ к элементам с помощью указателя и адресной арифметики. Например, пронумеруем все элементы:
Функция realloc()
Функция realloc() выполняет перераспределение памяти. Прототип функции:
В первом параметре функция realloc() принимает указатель на ранее выделенную динамическую память, а во втором — новый требуемый размер в байтах. Функция выделит динамическую память длиной newSize , скопирует в нее элементы из старой области памяти, освободит старую память и вернет указатель на новую область памяти. Новые элементы будут иметь произвольные значения, так называемый «мусор». Если новая длина меньше старой длины, то лишние элементы будут удалены. Если память не может быть выделена, то функция вернет нулевой указатель, при этом старая область памяти не изменяется (в этом случае возможны утечки памяти, если значение присваивается прежнему указателю).
Если в первом параметре указать значение NULL , то будет выделена динамическая память и функция вернет указатель на нее. Если во втором параметре указано значение 0 , то ранее выделенная динамическая память освобождается и функция вернет нулевой указатель.
Пример использования функции realloc() приведен в листинге 3.21.
Листинг 3.21. Функция realloc()
В языке C++ вместо функций malloc() , calloc() и realloc() лучше использовать класс vector , который реализует динамический массив. Следить за размерами динамического массива нет необходимости, т. к. управление динамической памятью осуществляется автоматически:

Учебник C++ (Qt Creator и MinGW) в формате PDF
Помощь сайту
ПАО Сбербанк:
Счет: 40817810855006152256
Реквизиты банка:
Наименование: СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК
Корреспондентский счет: 30101810500000000653
БИК: 044030653
КПП: 784243001
ОКПО: 09171401
ОКОНХ: 96130
Скриншот реквизитов
Динамическое распределение памяти с использованием операторов new и delete
Для С++-программы существует два основных способа хранения информации в основной памяти компьютера. Первый состоит в использовании переменных. Область памяти, предоставляемая переменным, закрепляется за ними во время компиляции и не может быть изменена при выполнении программы. Второй способ заключается в использовании C++-системы динамического распределения памяти. В этом случае память для данных выделяется по мере необходимости из раздела свободной памяти, который расположен между вашей программой (и ее постоянной областью хранения) и стеком. Этот раздел называется «кучей» (heap). (Расположение программы в памяти схематично показано на рис. 9.2.)
Система динамического распределения памяти — это средство получения программой некоторой области памяти во время ее выполнения.

Динамическое выделение памяти — это получение программой памяти во время ее выполнения. Другими словами, благодаря этой системе программа может создавать переменные во время выполнения, причем в нужном (в зависимости от ситуации) количестве. Эта система динамического распределения памяти особенно ценна для таких структур данных, как связные списки и двоичные деревья, которые изменяют свой размер по мере их использования. Динамическое выделение памяти для тех или иных целей — важная составляющая почти всех реальных программ.
Чтобы удовлетворить запрос на динамическое выделение памяти, используется так называемая «куча». Нетрудно предположить, что в некоторых чрезвычайных ситуациях свободная память «кучи» может исчерпаться. Следовательно, несмотря на то, что динамическое распределение памяти (по сравнению с фиксированным) обеспечивает большую гибкость, но и в этом случае оно имеет свои пределы.
Оператор new позволяет динамически выделить область памяти.
Язык C++ содержит два оператора, new и delete, которые выполняют функции по выделению и освобождению памяти. Приводим их общий формат.
переменная-указатель = new тип_переменной;
Оператор delete освобождает ранее выделенную динамическую память.
Здесь элемент переменная-указатель представляет собой указатель на значение, тип которого задан элементом тип_переменной. Оператор new выделяет область памяти, достаточную для хранения значения заданного типа, и возвращает указатель на эту область памяти. С помощью оператора new можно выделить память для значений любого допустимого типа. Оператор delete освобождает область памяти, адресуемую заданным указателем. После освобождения эта память может быть снова выделена в других целях при последующем new-запросе на выделение памяти.
Поскольку объем «кучи» конечен, она может когда-нибудь исчерпаться. Если для удовлетворения очередного запроса на выделение памяти не существует достаточно свободной памяти, оператор new потерпит фиаско, и будет сгенерировано исключение. Исключение— это ошибка специального типа, которая возникает во время выполнения программы. В общем случае ваша программа должна обработать подобное исключение и по возможности выполнить действие, соответствующее конкретной ситуации. Если это исключение не будет обработано вашей программой, ее выполнение будет прекращено.
Такое поведение оператора new в случае невозможности удовлетворить запрос на выделение памяти определено стандартом C++. На такую реализацию настроены также все современные компиляторы, включая последние версии Visual C++ и C++ Builder. Однако дело в том, что некоторые более ранние компиляторы обрабатывают new-инструкции по-другому. Сразу после изобретения языка C++ оператор new при неудачном выполнении возвращал нулевой указатель. Позже его реализация была изменена так, чтобы в случае неудачи генерировалось исключение, как было описано выше.
Рассмотрим пример программы, которая иллюстрирует использование операторов new и delete.
using namespace std;
p = new int; // Выделяем память для int-значения.
*p = 20; // Помещаем в эту область памяти значение 20.
cout << *р; // Убеждаемся (путем вывода на экран) в работоспособности этого кода.
delete р; // Освобождаем память.
Эта программа присваивает указателю р адрес (взятой из «кучи») области памяти, которая будет иметь размер, достаточный для хранения целочисленного значения. Затем в эту область памяти помещается число 20, после чего на экране отображается ее содержимое. Наконец, динамически выделенная память освобождается.
Благодаря такому способу организации динамического выделения памяти оператор delete необходимо использовать только с тем указателем на память, который был возвращен в результате new-запроса на выделение памяти. Использование оператора delete с другим типом адреса может вызвать серьезные проблемы.
Инициализация динамически выделенной памяти
Используя оператор new, динамически выделяемую память можно инициализировать. Для этого после имени типа задайте начальное значение, заключив его в круглые скобки. Например, в следующей программе область памяти, адресуемая указателем p, инициализируется значением 99.
using namespace std;
p = new int (99); // Инициализируем память числом 99.
cout << *p; // На экран выводится число 99.
Выделение памяти для массивов
С помощью оператора new можно выделять память и для массивов. Вот как выглядит общий формат операции выделения памяти для одномерного массива:
переменная-указатель = new тип [размер];
Здесь элемент размер задает количество элементов в массиве.
Чтобы освободить память, выделенную для динамически созданного массива, используйте такой формат оператора delete:
Здесь элемент переменная-указатель представляет собой адрес, полученный при выделении памяти для массива (с помощью оператора new). Квадратные скобки означают для C++, что динамически созданный массив удаляется, а вся область памяти, выделенная для него, автоматически освобождается.
Важно! Более старые С++-компиляторы могут требовать задания размера удаляемого массива, поскольку в ранних версиях C++ для освобождения памяти, занимаемой удаляемым массивом, необходимо было применять такой формат оператора delete:
delete [размер] переменная-указатель;
Здесь элемент размер задает количество элементов в массиве. Стандарт C++ больше не требует указывать размер при его удалении.
При выполнении следующей программы выделяется память для 10-элементного массива типа double, который затем заполняется значениями от 100 до 109, после чего содержимое этого массива отображается на экране.
using namespace std;
p = new double [10]; // Выделяем память для 10-элементного массива.
//Заполняем массив значениями от 100 до 109.
for(i=0; i<10; i++) р[i] = 100.00 + i;
// Отображаем содержимое массива.
delete [] p; // Удаляем весь массив.
При динамическом выделении памяти для массива важно помнить, что его нельзя одновременно и инициализировать.
Динамическое выделение памяти
хранятся на стеке. Как следует из названия, стек работает с переменными по схеме FILO (first in last out). Управление стеком происходит автоматически. При выходе переменной из области видимости, соответствующая ей в стеке память освобождается. Этот механизм позволяет разработчику не следить за удалением автоматических переменных. Стек работает очень быстро, но имеет ограниченный размер, который обычно не превосходит нескольких мегабайт.
Второй тип памяти — куча — устроен иначе. В куче объекты можно хранить в произвольном месте, создавать и удалять их в произвольном порядке, а размер кучи обычно значительно превосходит размер стека. Платить за эти преимущества приходится скоростью: работа с кучей происходит значительно медленнее, чем со стеком. Кроме того, объекты из кучи не удаляются автоматически.
Кучу имеет смысл использовать в двух случаях:
- Необходимо хранить большой объект. Хранение больших объектов на стеке может привести к его переполнению (stack overflow).
- Автоматическое управление памятью в стеке не соответствует логике программы. Чаще всего такая ситуация возникает, когда созданный объект должен продолжать свое существование после выхода из блока, в котором он был создан. Ниже мы рассмотрим пример.
Динамическое выделение памяти означает работу с кучей и является предметом данного раздела.
Ручное управление памятью
Начнем с обзора низкоуровневых инструментов, которые обычно не используются при разработке на современном C++. Знание эти инструментов, однако, может пригодиться при чтении старого кода и при работе со старыми компиляторами.
Создать объект в куче можно с помощью оператора new :
Оператор new возвращает указатель на область памяти в куче, в которой был создан объект. Создав объект с помощью оператора new , разработчик становится ответственными за его удаление. Освободить выделенную память и удалить объект можно с помощью оператора delete :
Вернемся к примеру из раздела про наследование, в котором мы строили модель символов в графическом текстовом редакторе. Напомним, что мы создали абстрактный базовый класс Character и два его наследника Letter и Digit . Допустим, нам надо реализовать функцию, которая возвращает полиморфный список символов (текст документа). Без динамического выделения нам будет сложно решить эту задачу. Например:
Объекты l1 , l2 , d1 и d2 в функции create_document созданы на стеке. При выходе из функции create_document для каждого объекта будет вызван деструктор и освобождена память на стеке. В этом виде функция возвращает список указателей на освобожденную память, что приводит к неопределенному поведению. Следующее изменение сделает код корректным:
Теперь память для объектов выделяется в куче, объекты продолжают существовать после выхода из функции. Использовать функцию create_document необходимо с учетом особенностей работы с динамической памятью. Напишем функцию print_document , которая вызывает create_document и выводит символы в стандартный поток вывода:
Использование функции print_document приводит к утечке памяти: при каждом ее вызове в куче выделяется память, которая никогда не освобождается. Более аккуратная реализация выглядит так:
Эта логика применима в любой ситуации с динамическим выделением памяти. Например, динамическое выделение памяти может происходить в конструкторе класса, а ее освобождение — в деструкторе.
Существуют версии операторов new и delete для создания и удаления массивов объектов:
При освобождении памяти важно использовать правильную версию оператора delete , что дополнительно усложняет разработку программ с ручным управлением памятью. Хорошей новостью является то, что оператор delete[] сам определяет размер удаляемого массива.
Далее мы рассмотрим более удобные и безопасные инструменты для работы с динамической памятью, которые доступны в современном C++.
Владение ресурсами и идиома RAII
Динамическое выделение памяти тесно связано с концепцией владения ресурсами. Ресурсом может быть не только память, но и, например, файловый дескриптор или сокет-соединение. В хорошо спроектированной программе структура владения ресурсами устроена ясно: каждым ресурсом владеет определенный объект, который отвечает за освобождение ресурса. Владение ресурсом можно передавать другому объекту, который вместе с ресурсом берет на себя ответственность за его освобождение.
Ясно организовать владение ресурсами практически в любой программе можно, следую идиоме RAII (resource acquisition is initialization, получение ресурса есть инициализация), которая (в несколько упрощенном виде) состоит в следующем:
- Каждый ресурс следует инкапсулировать в класс, при этом
- Конструктор выполняет выделение ресурса
- Деструктор выполняет освобождение ресурса
Мы уже видели пример RAII-объекта в C++, когда говорили про работу с файлами. Объект fstream владеет ресурсом — файловым дескриптором — и отвечает за его освобождение, а вся работа с файлом происходит через этот объект.
Умные указатели
В рамках идиомы RAII в современном C++ решены сложности работы с динамическим выделением памяти. Логика работы с динамической памятью инкапсулирована в специальных классах std::unique_ptr и std::shared_ptr , которые называют умными указателями. При конструировании такого объекта происходит выделение памяти, а при вызове деструктора — освобождение. Например:
При выходе из функции main выделенная в куче память корректно будет освобождена. Объекты std::unique_ptr и std::shared_ptr различаются с точки зрения владения объектом. Уникальный указатель std::unique_ptr единолично владеет ресурсом. Это означает, что не может быть два разных объекта std::unique_ptr не могут быть связаны с одним и тем же ресурсом. Это, например, означает, что объект std::unique_ptr не имеет копирующего конструктора и копирующего оператора присваивания. Вместо этого возможно использование перемещающего конструктор и перемещающего оператора присваивания. Например:
Объекты std::shared_ptr можно копировать. При этом несколько объектов std::shared_ptr оказываются связанными с одним ресурсом (динамически выделенной памятью). Освобождение памяти происходит в момент, когда последний ссылающийся на эту память объект std::shared_ptr вышел из области видимости. Необходимость подсчета ссылок в объектах std::shared_ptr приводит к определенным накладным расходам. Например объекты std::shared_ptr занимают больше памяти, чем объекты std::unique_ptr . Объекты std::unique_ptr при этом не уступают в производительности простым указателям.
Важно, что умные указатели сохраняют свойство полиморфности. Это позволяет нам модифицировать функцию create_document следующим образом:
и не заботится больше о ручном освобождении ресурсов. Несмотря на некоторую громоздкость синтаксиса умные указатели значительно упрощают разработку на C++. Мы рекомендуем использовать умные указатели вместо низкоуровневых операторов new и delete для работы с динамической памятью.
Сложность обращения с длинными названиями типов в C++ вроде std::list<std::unique_ptr<Character>> (и это не самый плохой случай) может быть преодолена с помощью псевдонимов. Например:
Виртуальный деструктор
В заключение этого раздела обсудим один тонкий момент, связанный с полиморфизмом и освобождением ресурсов в C++. Функция create_document корректно работает с динамической памятью. Однако, если использовать классы Character , Letter и Digit в том виде, в каком мы их оставили в разделе про наследование, то освобождение памяти при удалении объекта Document будет выполнено неверно. Контейнер std::list работает с (умными) указателями на объекты абстрактного класса Character . При удалении объекта std::list происходит удаление всех объектов типа std::unique_ptr<Character> , которые в свою очередь вызывают деструкторы объектов Character . Вместо этого мы хотим, чтобы для каждого объекта вызывался деструктор нужного класса-наследника. Вызов только деструктора базового класса снова может привести к утечке памяти.
Как для любого другого метода полиморфизм вызова деструктора реализуется через механизм виртуальных методов, в данном случае нам нужен виртуальный деструктор:
Поскольку ничего особенного, кроме собственно виртуальности, нам не нужно, мы доверили генерирование деструктора компилятору. Теперь наша программа, динамически выделяющая память для полиморфных объектов с помощью умных указателей, будет работать так, как нам нужно.
В любой иерархии классов деструктор базового класса рекомендуется объявлять виртуальным, чтобы избегать проблем с освобождением ресурсов объектами классов-наследников.
Резюме
В этом разделе мы обсудили основы работы с динамической памятью в C++. Рекомендуемыми инструментами работы с динамической памятью являются умные указатели std::unique_ptr и std::shared_ptr . Не забывайте объявлять деструктор базового класса виртуальным, если возможна работа с объектами классов-потомков через указатель на объект базового класса (а такая возможность есть всегда).
Динамическое выделение памяти в C++

Программирование и разработка
Обычно при использовании исходных кодов на языке программирования C++ компилятор вручную выделяет память переменной для хранения данных. Говорят, что это выделение статической памяти. Это фиксированная память, которую нельзя изменить после объявления. Для этого типа распределения памяти операционная система использует стек для хранения данных. При статическом распределении память выделяется до того, как исходный код начнет выполняться.
Принимая во внимание, что при динамическом выделении памяти память выделяется во время начала выполнения. Эта память выделяется программистом вручную во время выполнения, что также известно как выделение памяти во время выполнения в C++. Размер динамической памяти можно изменить в любом месте программы, потому что во время объявления мы не указываем размер, который можно зафиксировать. Мы только предоставляем значение непосредственно переменной.
Отличие выделения памяти от обычных переменных
В обычных переменных память, выделяемая компилятором, выделяется и освобождается автоматически. Когда память выделяется программистом динамически, ему приходится удалять или освобождать память, когда она бесполезна при дальнейшем выполнении исходного кода. Эта ситуация вызывает «утечку памяти», когда программа завершается, а память не освобождена.
Операторы для динамического размещения
В C++ в выделении и освобождении памяти помогают два оператора: «новый» и «удалить», которые используются для более эффективного выделения и освобождения памяти.
Новый оператор
Это означает потребность в выделении памяти. Новый оператор инициализирует память и возвращает адрес этой выделенной памяти в переменную-указатель, если памяти достаточно.
Удалить оператора
Как и оператор new, оператор удаления используется для удаления выделенной памяти. В C++ программист может использовать этот оператор для освобождения памяти.
Пример 1
В этом примере мы введем два указателя: один — указатель целочисленного типа, а другой — указатель с плавающей запятой. Указатели инициализируются с помощью знака звездочки с ними.
Используя эти два принтера, мы будем динамически выделять память.
Роль указателей в динамическом распределении:
Память пространства хранения разработана в виде блоков. Всякий раз, когда мы запускаем программу или выполняем какую-либо операцию, память выделяется для этой конкретной цели. Эта память имеет специальный адрес, связанный с программой, которая определяет, какому процессу или программе разрешен доступ к этой памяти. Доступ к любому слоту памяти осуществляется через адрес, которому он принадлежит. Итак, этот адрес хранится через указатели. Короче говоря, нам нужны указатели для доступа к памяти и, таким же образом, для выделения определенной части памяти для любой задачи. Указатели нужны для хранения адресов.Поскольку ключевое слово «новое» используется для динамического выделения памяти при ручном выделении, память выделяется компилятором. Нам не нужно выделять память во время выполнения. Но поскольку динамическое выделение является случайным, нам нужно идентифицировать указатели, и для процесса привязки используется этот новый оператор.
Точно так же привязан и плавающий указатель. После процесса привязки мы присвоим памяти любое значение, которое хотим зарезервировать для любой операции. Объявляя указатель, мы присваиваем памяти определенное значение.
Также объявляется значение float для точек с плавающей запятой. Отображение значений после присвоения.
Как мы уже говорили, оператор «new» используется для выделения памяти, а «delete» — для ее освобождения. Поэтому, как только вы завершите задачу или операцию в коде, мы удалим память, выделенную для задачи.
Лучше освободить эту часть памяти, чтобы ею мог воспользоваться любой другой процесс. Мы применим это распределение к обоим указателям.

Как только вы сохраните код в текстовом редакторе, терминал Ubuntu позволит вам выполнить исходный код внутри файла с помощью компилятора g++.
После выполнения вы увидите значения, присвоенные памяти.
Пример 2
В этом примере задействовано взаимодействие с пользователем. Мы возьмем числовую переменную, которая будет содержать значение от пользователя. Эта программа сохранит результат в среднем балле студента. Все результаты будут сохранены во время выполнения.
Когда пользователь вводит количество студентов, память выделяется для каждого числа. Здесь инициализируется указатель типа float, который будет использоваться при выделении памяти для результатов.
Мы берем указатель с плавающей запятой, так как GPA в десятичной системе счисления. Мы берем массив типа указателя для GPA, так как он может привести к количеству студентов.

Этот массив указателей с ключевым словом new свяжет выполнение с памятью. Средний балл будет введен для каждого студента. Поскольку нам неизвестно количество студентов, которых хочет добавить пользователь, мы использовали цикл for для ввода среднего балла до введенного числа. При каждом повторении цикла пользователю предлагается ввести результат, идентифицирующий учащегося. Как только результат будет сохранен, мы снова будем использовать цикл для отображения всех средних оценок учащихся. В конце массив указателей удаляется, так как цель динамического хранения достигнута.
Теперь мы выполним вышеупомянутый код. Сначала пользователю будет предложено ввести количество студентов. Затем будет введен средний балл для каждого студента.

Пример 3
В этом примере используются операторы new и delete для объекта класса. Этот класс содержит закрытую переменную целочисленного типа, в которой хранится возраст. В общедоступной части класса создается конструктор, который инициализирует возраст числом «10». Здесь используется другая функция, которая будет отображать возраст, который инициализируется в конструкторе.

Теперь перейдем к основной программе динамического размещения. Объект класса создается динамически.

Когда объект будет сформирован, конструктор будет реализован автоматически. Будет сделан вызов функции, чтобы получить возраст. Это будет сделано через ptr.
И в конце память будет освобождена.

Заключение
Динамическое выделение памяти выделяется программистом во время выполнения вместо фиксированной памяти, определяемой компилятором. Это распределение является случайным и может быть устранено после его использования. Принимая во внимание, что в большинстве случаев перед удалением процесс выполнения останавливается, и это динамическое выделение вызывает утечку памяти. Мы реализовали это явление в различных подходах в системе Ubuntu Linux, используя язык программирования C++.