динамический массив в c код
Статья Как создать динамический массив в c#
Создание динамического массива в языке c#
В языке c# под словом массив подразумевается объект с заранее заданным неизменяемым размером. То есть, к примеру, если Вы создали массив, который содержит пять элементов, то увеличить данный размер динамически Вы уже не сможете, так как он является фиксированным. В этом можно легко убедиться, воспользовавшись свойством IsFixedSize.
С помощью данного свойства Вы можете определить, имеет ли созданный массив фиксированную длину. Если результатом является значение true, как в данном примере, то это значит, что мы не можем добавлять или удалять элементы в уже созданном массиве, то есть изменять его текущий размер. Но, при этом мы можем изменять его существующие элементы.
Так как задача довольно актуальная, то какой-то способ решения всё-таки должен быть. И он есть. Если Вам необходимо создать динамический массив, то Вы можете воспользоваться, например методом Resize класса System.Array.
Данный метод принимает два параметра: имя массива и его новый размер. В ходе выполнения метода, будет создан новый массив указанной нами длины, после чего все значения из старого массива будут скопированы в него. В результате мы получаем динамический массив. Задача решена.
Либо мы можем схитрить и всё-таки решить данную задачу, воспользовавшись обобщенным списком List класса System.Collections.Generic, например:
Вместо массива мы используем список, который, как уже говорилось ранее, по умолчанию является динамическим. С помощью него мы выполняем всю необходимую работу и как только добиваемся нужного результата, то с помощью метода ToArray преобразуем список в массив.
Динамические массивы в C++
Обычно, объем памяти, необходимый для той или иной переменной, задается еще до процесса компиляции посредством объявления этой переменной. Если же возникает необходимость в создание переменной, размер которой неизвестен заранее, то используют динамическую память. Резервирование и освобождение памяти в программах на C++ может происходить в любой момент времени. Осуществляются операции распределения памяти двумя способами:
Функция malloc резервирует непрерывный блок ячеек памяти для хранения указанного объекта и возвращает указатель на первую ячейку этого блока. Обращение к функции имеет вид:
void *malloc(size);
Здесь size — целое беззнаковое значение, определяющее размер выделяемого участка памяти в байтах. Если резервирование памяти прошло успешно, то функция возвращает переменную типа void *, которую можно привести к любому необходимому типу указателя.
Функция — calloc также предназначена для выделения памяти. Запись ниже означает, что будет выделено num элементов по size байт.
void *calloc (nime, size);
Эта функция возвращает указатель на выделенный участок или NULL при невозможности выделить память. Особенностью функции является обнуление всех выделенных элементов.
Функция realloc изменяет размер выделенной ранее памяти. Обращаются к ней так:
char *realloc (void *p, size);
Здесь p — указатель на область памяти, размер которой нужно изменить на size. Если в результате работы функции меняется адрес области памяти, то новый адрес вернется в качестве результата. Если фактическое значение первого параметра NULL, то функция realloc работает также, как и функция malloc, то есть выделяет участок памяти размером size байт.
Для освобождения выделенной памяти используется функция free. Обращаются к ней так:
void free (void *p size);
Здесь p — указатель на участок памяти, ранее выделенный функциями malloc, calloc или realloc.
Операторы new и delete аналогичны функциям malloc и free. New выделяет память, а его единственный аргумент — это выражение, определяющее количество байтов, которые будут зарезервированы. Возвращает оператор указатель на начало выделенного блока памяти. Оператор delete освобождает память, его аргумент — адрес первой ячейки блока, который необходимо освободить.
Динамический массив — массив переменной длины, память под который выделяется в процессе выполнения программы. Выделение памяти осуществляется функциями calloc, malloc или оператором new. Адрес первого элемента выделенного участка памяти хранится в переменной, объявленной как указатель. Например, следующий оператор означает, что описан указатель mas и ему присвоен адрес начала непрерывной области динамической памяти, выделенной с помощью оператора new:
int *mas=new int[10];
Выделено столько памяти, сколько необходимо для хранения 10 величин типа int.
Фактически, в переменной mas хранится адрес нулевого элемента динамического массива. Следовательно, адрес следующего, первого элемента, в выделенном участке памяти — mas+1, а mas+i является адресом i-го элемента. Обращение к i-му элементу динамического массива можно выполнить, как обычно mas[i], или другим способом *(mas +i). Важно следить за тем, чтобы не выйти за границы выделенного участка памяти.
Когда динамический массив (в любой момент работы программы) перестает быть нужным, то память можно освободить с помощью функции free или оператора delete.
Предлагаю рассмотреть несколько задач, закрепляющих данный урок:
Задача 1
Найти сумму вещественных элементов динамического массива.
Динамическое выделение памяти в Си
Очень часто возникают задачи обработки массивов данных, размерность которых заранее неизвестна. В этом случае возможно использование одного из двух подходов:
Для использования функций динамического выделения памяти необходимо описать указатель, представляющий собой начальный адрес хранения элементов массива.
Начальный адрес статического массива определяется компилятором в момент его объявления и не может быть изменен.
Для динамического массива начальный адрес присваивается объявленному указателю на массив в процессе выполнения программы.
Стандартные функции динамического выделения памяти
Функции динамического выделения памяти находят в оперативной памяти непрерывный участок требуемой длины и возвращают начальный адрес этого участка.
Функции динамического распределения памяти:
Для использования функций динамического распределения памяти необходимо подключение библиотеки :
Для определения размера массива в байтах, используемого в качестве аргумента функции malloc() требуется количество элементов умножить на размер одного элемента. Поскольку элементами массива могут быть как данные простых типов, так и составных типов (например, структуры), для точного определения размера элемента в общем случае рекомендуется использование функции
«Правилом хорошего тона» в программировании является освобождение динамически выделенной памяти в случае отсутствия ее дальнейшего использования. Однако если динамически выделенная память не освобождается явным образом, она будет освобождена по завершении выполнения программы.
Динамическое выделение памяти для одномерных массивов
Форма обращения к элементам массива с помощью указателей имеет следующий вид:
Пример на Си : Организация динамического одномерного массива и ввод его элементов.
Результат выполнения программы:
Динамическое выделение памяти для двумерных массивов
Пусть требуется разместить в динамической памяти матрицу, содержащую n строк и m столбцов. Двумерная матрица будет располагаться в оперативной памяти в форме ленты, состоящей из элементов строк. При этом индекс любого элемента двумерной матрицы можно получить по формуле
index = i*m+j;
Рассмотрим матрицу 3×4 (см. рис.)
Индекс выделенного элемента определится как
index = 1*4+2=6
Объем памяти, требуемый для размещения двумерного массива, определится как
n·m·(размер элемента)
Однако поскольку при таком объявлении компилятору явно не указывается количество элементов в строке и столбце двумерного массива, традиционное обращение к элементу путем указания индекса строки и индекса столбца является некорректным:
Правильное обращение к элементу с использованием указателя будет выглядеть как
Пример на Си Ввод и вывод значений динамического двумерного массива
Результат выполнения
Графически такой способ выделения памяти можно представить следующим образом.
При таком способе выделения памяти компилятору явно указано количество строк и количество столбцов в массиве.
Пример на Си
Результат выполнения программы аналогичен предыдущему случаю.
С помощью динамического выделения памяти под указатели строк можно размещать свободные массивы. Свободным называется двухмерный массив (матрица), размер строк которого может быть различным. Преимущество использования свободного массива заключается в том, что не требуется отводить память компьютера с запасом для размещения строки максимально возможной длины. Фактически свободный массив представляет собой одномерный массив указателей на одномерные массивы данных.
Пример на Си : Свободный массив
Результат выполнения
Перераспределение памяти
Если размер выделяемой памяти нельзя задать заранее, например при вводе последовательности значений до определенной команды, то для увеличения размера массива при вводе следующего значения необходимо выполнить следующие действия:
Все перечисленные выше действия (кроме последнего) выполняет функция
Размер блока памяти, на который ссылается параметр ptr изменяется на size байтов. Блок памяти может уменьшаться или увеличиваться в размере. Содержимое блока памяти сохраняется даже если новый блок имеет меньший размер, чем старый. Но отбрасываются те данные, которые выходят за рамки нового блока. Если новый блок памяти больше старого, то содержимое вновь выделенной памяти будет неопределенным.
Пример на Си Выделить память для ввода массива целых чисел. После ввода каждого значения задавать вопрос о вводе следующего значения.
Результат выполнения
Комментариев к записи: 80
cout «_asm code started working» endl;
_asm <
pushf // помещаем регистр флагов в стек
pop var // извлекаем операнд из стека (шта?)
>
cout «_asm code finished working» endl;
// Вывод var
cout var endl;
short *var;
var = new short[1];
cout «_asm code started working» endl;
_asm <
pushf // помещаем регистр флагов в стек
pop *var[0] // извлекаем операнд из стека (шта?)
>
cout «_asm code finished working» endl;
// Вывод var
cout *var[0] endl;
#include
#include
#include
#include
#include
#include
#include
#include
#define _CRT_SECURE_NO_WARNINGS
#include «stdlib.h»
#include «stdio.h»
#include «conio.h»
#include «math.h»
#include
#include «locale.h»
#include «string.h»
#include «windows.h»
#include «time.h»
a = ( int **)realloc(a, (2*n*m) * sizeof ( int ));
for (i = n; i // цикл по строкам
<
for (j = 0; j // цикл по столбцам
<
a[i][j] = b[counter][j];
counter++;
>
printf( «\n» );
>
// Очистка памяти
for (i = 0; i // цикл по строкам
free(a[i]); // освобождение памяти под строку
free(a);
for (i = 0; i // цикл по строкам
free(b[i]); // освобождение памяти под строку
free(b);
Динамические массивы и переменные: легко и просто!
Всем привет! В этой статье мы создадим массив и переменные применяя указатели. Если вы еще не почитали прошлую (начальную) статью про указатели, то советуем сначала изучить ее. Ну а если вы это все знаете, то погнали!
Быстрый переход по статье.
Что такое динамические переменные
Динамические переменные — это переменные, которые созданы напрямую с помощью указателей. Для них существует функция удаление (это мы разберем ниже).
На каждый тип данных выделяется разное количество ячеек.
Как создать динамические переменные в C++
Для создания динамических переменных нам понадобится применять конструкцию ниже:
Давайте подробно ее разберем:
Вы должны знать! Если тип переменной отличается от типа указателя — то эта динамическая переменная будет весить больше в оперативной памяти, чем такая же переменная с одинаковыми типами!
Пример использования динамических переменных
Внизу мы решили использовать динамические переменные:
Удаление динамических переменных
Как мы говорили выше, у нас есть возможность освобождать память переменной или, если понятным языком, удалять переменную из оперативной памяти ПК.
Чтобы его использовать, нужно применить конструкцию ниже:
Вы должны обратить внимание на отсутствие оператора * перед именем переменной. Многие начинающие прогеры забывают про это и в дальнейшем пытаются найти ошибку часами.
Статическое и динамическое объявление переменных
Статическое объявление переменных имеет такой вид: int number;
Использование динамических переменных имеет маленький плюс. Он заключается в освобождении памяти переменной до завершения программы. Благодаря этому мы можем сначала удалить переменную, а потом ее снова создать в другом участке программы (когда это нам будет нужно).
Что такое динамические массивы
Мы уже знакомы с миром массивов в C++. Мы не раз создавали их на определенное количество ячеек и при этом использовали статическое создание массивов.
Но еще ни разу не затрагивали их использование с указателями!
Мы создавали массивы на сто тысяч элементов, а то и больше. И не один раз бывало, что большое количество ячеек оставались неиспользованными. Это является неправильным применением оперативной памяти в ПК.
Чтобы мы бесполезно не использовали оперативную память в компьютере, нам понадобится оперировать с указателями в свете массивов.
Нам нужно вспомнить, что для создания статического массива количество ячеек нужно задавать числовой константой (а не переменной). Это очень неприятно, потому что в программе мы не знаем, сколько нам может понадобится ячеек.
Например, пользователь захотел вписать 1000 чисел в массив, а мы из-за незнания этого факта сделали массив всего лишь на 500 ячеек.
Динамический массив — это массив, у которого количество ячеек можно задавать и переменной, и числовой константой. Это большой плюс перед использованием статического массива.
Как работают динамические массивы
Как создать динамический массив в C++
Чтобы создать динамический массив мы будем использовать конструкцию ниже:
Массивы в C++
Продолжаем серию «C++, копаем вглубь». Цель этой серии — рассказать максимально подробно о разных особенностях языка, возможно довольно специальных. Это четвертая статья из серии, первые три, посвященные перегрузке в C++, находятся здесь, здесь и здесь.
Эта статья посвящена массивам. Массивы можно отнести к наиболее древним слоям C++, они пришли из первых версий C. Тем не менее, массивы вошли в объектно-ориентированную систему типов C++, хотя и с определенными оговорками. Программисту важно знать об этих особенностях, чтобы избежать потенциальных ошибок. В статье также рассмотрено другое наследие C – тривиальные типы и неинициализированные переменные. Часть нововведений C++11, С++14, С++17 затрагивают работу с массивами, все эти новые возможности также подробно описаны. Итак, попробуем рассказать о массивах все.
Оглавление
1. Общие положения
Массив является простейшим агрегатным типом. Он моделирует набор однотипных элементов, расположенных подряд в непрерывном отрезке памяти. Массивы в той или иной форме поддерживаются практически всеми языками программирования и неудивительно, что они появились в первых версиях C и затем стали частью C++.
1.1. Объявление массивов
Если T некоторый тип, N константа или выражение, вычисляемое во время компиляции, то инструкция
Такие массивы еще называют встроенными массивами (regular arrays), чтобы подчеркнуть отличие от других вариантов массивов, термин «массив» используется в программировании и в том числе в C++ достаточно широко.
Вот примеры правильных объявлений массивов:
А вот примеры некорректных объявлений массивов:
Выход за границы массива не контролируется, ошибка может привести к неопределенному поведению.
В одной инструкции можно объявить несколько массивов, но размер должен быть указан для каждого.
Для типов массивов можно вводить псевдонимы. Можно использовать традиционный вариант с ключевым словом typedef :
или более современный (C++11) с ключевым словом using :
После этого массивы объявляются как простые переменные:
Это будет то же самое, что
1.2. Операторы и стандартные функции для работы с массивами
Для работы с массивами можно использовать оператор sizeof и несколько стандартных функций и макросов.
Оператор sizeof возвращает полный размер массива в байтах, то есть размер элемента умноженный на размер массива.
А также в стандартных алгоритмах:
1.3. Размещение в памяти
Если массив объявлен статически, то есть в глобальной области видимости, в области видимости пространства имен или в качестве статического члена класса, то он размещается в статической памяти. Массивам, объявленным локально, память выделяется на стеке. (Естественно, надо учитывать ограниченный размер стека при выборе размера локальных массивов.) Нестатические члены класса размещаются в границах экземпляра класса. Динамические массивы (см. раздел 6) размещаются в динамической памяти.
1.4. Ограничения на типы элементов массивов
Нельзя объявить массив ссылок.
Вместо этого можно использовать массив константных указателей.
(Синтаксис инициализации массивов будет обсуждаться в разделе 3.2.)
Нельзя объявить массив функций.
Вместо этого можно использовать массив указателей на функцию.
Квалификатор const не применим к типу массива, а только к типам его элементов.
2. Сведение и копирование массивов
В данном разделе рассматриваются особенности массивов, которые выделяют их из общей системы типов C++.
2.1. Сведение
Конечно, тесную связь массивов и указателей отрицать нельзя. Вот стандартный (в стиле C) способ обработать все элементы массива:
Но все же сведение можно отнести к сишным архаизмам и с ним надо быть внимательным и аккуратным, иначе можно столкнуться с не самыми приятными неожиданностями.
Вот как сведение влияет на объявления функций. Функции
не являются перегруженными функциями — это одно и то же. Размер надо передавать дополнительным параметром или использовать специальное соглашение для определения размера (например, завершающий ноль для строк).
При внешнем связывании массива также происходит сведение.
Для размера также надо использовать дополнительную переменную или использовать специальное соглашение для определения размера.
При объявлении переменной с помощью ключевого слова auto также происходит сведение.
При конкретизации шаблона функции
тип параметра шаблонной функции также будет выведен как указатель, если аргумент является массивом.
Сведение вызывает дополнительные проблемы при использовании наследования. (В C ведь нет наследования.) Рассмотрим пример.
Следующий код компилируется без ошибок и предупреждений.
2.2. Копирование
Наряду со сведением (и тесно связанная с ним) есть еще одна особенность типа массива, которая делает его в некотором смысле «неполноценным». Массивы не поддерживают привычный синтаксис инициализации и присваивания, основанный на семантике копирования:
Также функция не может возвращать массив.
Но если массив является членом класса/структуры/объединения, то проблемы с копированием (а также сведение) отсутствуют.
Для этой структуры компилятор сгенерирует копирующий конструктор по умолчанию и соответствующий оператор присваивания, которые без проблем скопируют массив.
3. Инициализация массивов
Для описания правил инициализации массивов необходимо кратко рассказать о тривиальных типах.
3.1. Тривиальные типы и неинициализированные переменные
Конструкторы и деструкторы можно назвать ключевыми элементами объектной модели С++. При создании объекта обязательно вызывается конструктор, а при удалении — деструктор. Но проблемы совместимости с С вынудили сделать некоторое исключение, и это исключение называется тривиальные типы. Они введены для моделирования сишных типов и сишного жизненного цикла переменных, без обязательного вызова конструктора и деструктора. Сишный код, если он компилируется и выполняется в С++, должен работать так же как в С. К тривиальным типам относятся числовые типы, указатели, перечисления, а также классы, структуры, объединения и массивы, состоящие из тривиальных типов. Классы и структуры должны удовлетворять некоторым дополнительным условиям: отсутствие пользовательского конструктора, деструктора, копирования, присваивания, виртуальных функций.
Переменная тривиального типа будет неинициализированной, если не использовать какой-нибудь вариант явной инициализации. Для тривиального класса компилятор может сгенерировать конструктор по умолчанию и деструктор. Конструктор по умолчанию обнуляет объект, деструктор ничего не делает. Но этот конструктор будет сгенерирован и использован только, если использовать какой-нибудь вариант явной инициализации, иначе переменная останется неинициализированной.
Неинициализированная переменная устроена следующим образом: если она объявлена в области видимости пространства имен (глобально), будет иметь все биты нулевыми, если локально, или создана динамически, то получит случайный набор битов. Понятно, что использование такой переменной может привести к непредсказуемому поведению программы. Массивы достаточно часто имеют тривиальный тип и поэтому эта проблема для них весьма актуальна.
Неинициализированные константы тривиального типа выявляет компилятор, иногда он выявляет и другие неинициализированные переменные, но с этой задачей лучше справляются статические анализаторы кода.
3.2. Синтаксис инициализации массивов
3.2.1. Общие положения
Если не использовать явную инициализацию, то для массивов нетривиального типа гарантируется вызов конструктора по умолчанию для каждого элемента. Естественно, что в этом случае такой конструктор должен быть, иначе возникает ошибка. Но для массивов тривиального типа или, если конструктор по умолчанию отсутствует или не устраивает, необходимо использовать явную инициализацию.
Со времен C массивы можно было инициализировать с помощью синтаксиса агрегатной инициализации:
В С++11 появилась универсальная инициализация (uniform initialization) и теперь можно инициализировать так:
Для универсальной инициализации также можно использовать =, и различать эти два типа инициализации не всегда просто, а, скорее всего, не очень нужно.
Размер массива можно не указывать, тогда он определится по числу инициализаторов.
Если размер массива указан, то число инициализаторов не должно быть больше размера массива. Если размер массива больше числа инициализаторов, то для оставшихся элементов гарантируется вызов конструктора по умолчанию (который, естественно, должен быть), в том числе и для тривиальных типов. Таким образам, указав пустой список инициализации, мы гарантируем вызов конструктора по умолчанию для всех элементов массива тривиального типа.
Массивы констант тривиального типа требуют обязательного списка инициализации.
Число инициализаторов может быть меньше размера массива, в этом случае оставшиеся элементы инициализируются конструктором по умолчанию.
Символьные массивы можно инициализировать строковым литералом.
Размер такого массива будет на единицу больше числа символов строки, нужно хранить завершающий нулевой символ.
3.2.2. Инициализация членов класса
В С++11 появилась возможность инициализировать массивы, являющиеся нестатическими членами класса. Это можно сделать двумя способами: непосредственно при объявлении или в списке инициализации членов при определении конструктора.
Правда в этом случае надо всегда явно задавать размер массива, неявное определение размера через список инициализации не разрешается.
Статические массивы, как и ранее, можно инициализировать только при определении, размер массива может быть определен через список инициализации.
3.2.3. Требования к инициализаторам
Выражения, стоящие в списке инициализации, вычисляются непосредственно перед инициализацией, они не обязаны быть известными на стадии компиляции (конечно, за исключением массивов, объявленных как constexpr ). Требования к элементам списка инициализации такие же как и к аргументу функции, имеющей параметр того же типа, что и элемент массива — должно существовать неявное преобразование от типа элемента списка инициализации к типу элемента массива. Пусть у нас есть объявление массива:
Наличие нужного преобразования эквивалентно корректности инструкции
Элемент списка инициализации может быть сам списком инициализации. В этом случае корректность этой инструкции также гарантирует корректную инициализацию элемента массива.
Этот пример также демонстрирует как с помощью списка инициализации мы можем создать массив для типа у которого нет конструктора по умолчанию. Но в этом случае число инициализаторов должно совпадать с размером массива.
4. Указатели и ссылки на массивы
4.1. Указатели на массивы
Пусть у нас объявлен массив
Указатель на этот массив объявляется и инициализируется следующим образом:
Указатель на массив — это не указатель на первый элемент (хотя побитово они, конечно, совпадают), здесь нет никакого сведения. Это полноценный тип, который «знает» размер массива. Поэтому при инициализации размеры должны совпадать.
При инкременте указатель на массив увеличивается на размер всего массива, а не на размер элемента.
Для доступа к элементу массива через указатель надо использовать оператор * и индексатор.
При использовании псевдонимов можно получить более привычный синтаксис объявления указателя на массив.
Понимание указателей на массивы необходимо для правильной работы с многомерными массивами, которые подробно будут рассмотрены далее.
4.2. Ссылки на массивы
Пусть у нас объявлен массив
Ссылка на этот массив объявляется и инициализируется следующим образом:
Также ссылку на массив можно инициализировать разыменованным указателем на массив.
Как и указатель, ссылка «знает» размер массива. Поэтому при инициализации размеры должны совпадать.
Доступ к элементу массива через ссылку осуществляется так же, как и через идентификатор массива.
Ссылки на массивы как раз и являются теми средствами, с помощью которых можно обойти сведение.
При использовании псевдонимов можно получить более привычный синтаксис объявления ссылки на массив.
При конкретизации шаблона функции
тип параметра шаблонной функции также будет выведен как ссылка на массив, если аргумент является массивом.
Особенно удобно использовать шаблоны с выводом типа и размера массива.
5. Многомерные массивы
Если T некоторый тип, N и M выражения, допустимые для определения размера массива, то инструкция
Сведение преобразует массив к указателю на элемент. Для двумерного массива этот элемент сам является массивом, а значит двумерный массив сводится к указателю на массив.
Таким образом, при передаче двумерного массива в функцию следующие варианты объявления соответствующего параметра эквивалентны:
Это означает, что внешний размер двумерного массива теряется и его надо передавать отдельным параметром.
При использовании псевдонимов можно получить более лаконичный синтаксис объявления двумерных массивов.
Это то же самое, что
Двумерные массивы инициализируются следующим образом:
Можно получить указатель на двумерный массив:
Также можно получить ссылку. Вот пример использования ссылки на двумерный массив.
Двумерный массив хорошо согласуется с математическими матрицами. В объявлении
6. Динамические массивы
В C++ отсутствует тип «динамический массив». Имеются только операторы для создания и удаления динамического массива, доступ к нему осуществляется через указатели на начало массива (своего рода полное сведение). Размер такого массива надо хранить отдельно. Динамические массивы желательно инкапсулировать в C++ классы.
6.1. Создание и удаление динамического массива
Если T некоторый тип, n переменная, значение которой может определяются в процессе выполнения программы, то инструкция
Если тип T тривиальный, то элементы будут иметь случайное значение, в противном случае для инициализации элементов будет использован конструктор по умолчанию.
В C++11 появилась возможность использовать список инициализации.
Если число инициализаторов больше размера массива, то лишние не используются (компилятор может выдать ошибку, если значение n известно на стадии компиляции). Если размер массива больше числа инициализаторов, то для оставшихся элементов гарантируется вызов конструктора по умолчанию, в том числе и для тривиальных типов. Таким образам, указав пустой список инициализации, мы гарантируем вызов конструктора по умолчанию для всех элементов массива тривиального типа.
При этом, если при создании массива использовался конструктор, то для всех элементов массива вызывается деструктор в порядке, обратном вызову конструктора (деструктор не должен выбрасывать исключений), затем выделенная память освобождается.
6.2. Динамические массивы и интеллектуальные указатели
В C++14 появилась возможность создать динамический массив и инициализировать им экземпляр std::unique_ptr<> с помощью std::make_unique<> :
При этом гарантируется инициализация элементов массива по умолчанию, в том числе и для тривиальных типов.
Интеллектуальный указатель std::shared_ptr<> стал поддерживать такую специализацию только в C++17, а использование std::make_shared<> для этой специализации появилось только в C++20.
6.3. Многомерные динамические массивы
При использовании псевдонимов можно получить более лаконичный синтаксис.
Используя перегрузку оператора [] легко создать класс, который хранит данные в одномерном массиве, но при этом предоставляет интерфейс многомерного массива. Вот пример предельно упрощенного класса матрицы.
Вот пример использования:
7. Использование массивов в шаблонах
Тип массива можно использовать в качестве шаблонных аргументов и для специализации шаблонов классов.
В стандартной библиотеке частичная специализация интеллектуального указателя std::unique_ptr<> и std::shared_ptr<> для массивов используется для управления жизненным циклом динамического массива, подробнее см. раздел 6.2.
В качестве реального примера использования этих свойст типов приведем немного упрощенное определение перегруженного варианта шаблона функции std::make_unique<> для массивов (см. раздел 6.2):
8. Стандартные альтернативы массивам
Стандартная библиотека предоставляет несколько классов (точнее шаблонов классов), которые рекомендуется использовать вместо массивов.
Этот шаблон поддерживает индексатор и традиционный интерфейс стандартного контейнера.
Список литературы
[Josuttis]
Джосаттис, Николаи М. Стандартная библиотека C++: справочное руководство, 2-е изд.: Пер. с англ. — М.: ООО «И.Д. Вильямс», 2014.