Как удалить массив из памяти

Обновлено: 03.07.2024

Может ли кто-нибудь из вас (пожалуйста, только эксперты) объяснить, какое из них верно первое или второе? Потому что мы знаем, что в фоновом процессоре нет 2D, 3D, 4D. размер для памяти. То есть после того, как мы хотим создать один 2D или 3D мерный массив, ему последовательно выделяется 1D массив в памяти. Пожалуйста, не говорите, что вам нужно освободить каждый элемент массива. Можете ли вы объяснить, почему первые члены неверны как ядро ​​​​(включая память)? Потому что мы не получаем никакой ошибки для первых условий на компиляторе. Пожалуйста, доказательство. Спасибо.

Во-первых:

Второй:
int main()
int **container = new int*[n];
for(int i = 0; i c++

Я думаю, что количество удалить должно соответствовать количеству новых.

На самом деле все просто — для каждого нового должно быть соответствующее удаление. Вы вызываете new n+1 раз, поэтому вам следует вызывать delete n+1 раз, иначе произойдет утечка памяти.

Вы не выделяете 2D-массив — вы делаете n+1 отдельных выделений, совершенно не связанных друг с другом, насколько может судить компилятор. Возможно, даже вероятно, что они не будут следовать друг за другом в памяти.

Можете ли вы ожидать, что delete[] container1 каким-то образом узнает об освобождении всех остальных новых аллокаций int[size]? Или что цикл каким-то образом создаст два последовательных блока памяти, при этом нечетные выделения будут переданы первому, а четные - второму, основываясь только на том, куда присваивается указатель после выполнения выделения?

В качестве первого примера рассмотрим простой пример. Предположим, что n равно 2, size равен 3, а указатели и int равны 4 байтам.

После строки 3 контейнер указывает на область, способную хранить два типа int*: например, от 0x1000 до 0x1007.

После первого выполнения строки 5 container[0] указывает на область, способную хранить три целых числа: например, от 0x2000 до 0x200b

После второго выполнения строки 5 container[1] . от 0x3000 до 0x300b.

После строки 8 значение container неопределенно, а память с 0x1000 по 0x1007 освобождена. Хотя container[0] и container[1] больше не существуют, память с 0x2000 по 0x200b и с 0x3000 по 0x300b по-прежнему выделяется. Поскольку указателей на эту память нет, ее нельзя освободить или использовать для каких-либо целей. Эта память останется недоступной для жизни вашей программы. Такая ситуация называется утечкой памяти.

У вас не должно возникнуть проблем с пониманием того, почему второй пример устраняет эту проблему.

(1) обычное удаление Освобождает блок памяти, на который указывает ptr (если он не нулевой), освобождая место для хранения, ранее выделенное для него вызовом оператора new[] и делая этот указатель недействительным.
(2) не удалять То же, что и выше (1).
(3) размещение delete Ничего не делает.

(1) обычное удаление Освобождает блок памяти, на который указывает ptr (если он не нулевой), освобождая место для хранения, ранее выделенное для него вызовом оператора new[] и делая этот указатель недействительным.
Определение по умолчанию вызывает ::operator delete(ptr) .
(2) не удалять То же, что и выше (1).
Определение по умолчанию вызывает первую версию (1): ::operator delete[](ptr) .
(3) размещение delete Ничего не делает.

(1) обычное удаление Освобождает блок памяти, на который указывает ptr (если он не нулевой), освобождая место для хранения, ранее выделенное для него вызовом оператора new[] и делая этот указатель недействительным.
Определение по умолчанию вызывает ::operator delete(ptr) .
(2) не удалять То же, что и выше (1).
Определение по умолчанию вызывает первую версию (1): ::operator delete[](ptr) .
(3) размещение delete Ничего не делает.
(4) (5) с размером Аналогично (1) и (2) соответственно.
Определение по умолчанию просто вызывает соответствующую версию: либо (1), либо (2).
Они обеспечивают точку оптимизации для пользовательских реализаций: они вызываются с тем же аргументом size, который используется при вызове соответствующего оператора new[]|функции распределения.

  • Глобальный: все три версии оператора delete[] объявляются в глобальном пространстве имен, а не в пространстве имен std.
  • Неявно: освобождающие версии (т. е. все, кроме (3)) неявно объявляются в каждой единице трансляции программы C++, независимо от того, включен ли заголовок или нет.
  • Заменяемые: Освобождающие версии (т. е. все, кроме (3)) также заменяемые: программа может предоставить собственное определение, которое заменяет предоставленное по умолчанию для привести к результату, описанному выше, или может перегрузить его для определенных типов.

Функция освобождения массива для объекта класса — это функция-член с именем operator delete[] , если она существует.Во всех остальных случаях это глобальный оператор функции delete[] (т. е. эта функция или более конкретная перегрузка). Если перед выражением delete[] стоит оператор области видимости (т. е. ::оператор delete[] ), рассматриваются только глобальные функции освобождения массива.

Выражения

delete[], использующие глобальные функции освобождения массива, всегда вызывают сигнатуры с одним аргументом (например, (1)).

Выражения

delete[], использующие глобальные функции освобождения массива, всегда используют сигнатуру, которая принимает либо указатель (например, (1)), либо указатель и размер (например, (4)). Всегда предпочтительнее версия с size (4), если только перегрузка не обеспечивает лучшее соответствие для типа указателя.

Другие подписи ((2) и (3)) никогда не вызываются выражением delete[] (выражение delete[ ] всегда вызывает обычную версию этой функции и ровно один раз для каждого из ее аргументов). Эти другие сигнатуры автоматически вызываются new[]-expression только в случае сбоя их конструкции объекта (например, если конструктор объекта бросает вызов во время создания с помощью new[]-expression< /i> с nothrow вызывается функция сопоставления оператора delete[], принимающая аргумент nothrow).

Не являющиеся членами функции освобождения массива не должны объявляться в пространстве имен, отличном от глобального пространства имен.

Параметры

ptr Указатель на освобождаемый блок памяти, приведенный к типу void* .
Если это нулевой указатель, функция ничего не делает.

В противном случае это значение указателя должно было быть возвращено предыдущим вызовом оператора new[] и еще не было освобождено предыдущим вызовом этой функции.

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

nothrow_constant Константа nothrow . Этот параметр игнорируется в определении по умолчанию.
nothrow_t — это тип константы nothrow.
voidptr2 Пустой указатель. Значение игнорируется в определении по умолчанию. size Первый аргумент, передаваемый функции выделения при выделении блока памяти.
std::size_t — целочисленный тип без знака.

Возвращаемое значение

Пример

Гонки данных

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

Безопасность исключений

Гарантия отсутствия генерации: эта функция никогда не генерирует исключений.

Обратите внимание, что недопустимое значение ptr или значение size, не совпадающее со значением, переданным функции распределения, приводит к неопределенному поведению.

См. также

оператор new[] Выделить место для хранения массива (функция) оператор delete Освободить место для хранения (функция)

Стажировка в OpenGenus

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

  • Если массив объявлен статически, нам не нужно удалять массив, так как он удаляется в конце программы/блока, в котором он был объявлен.
  • Если массив объявлен динамически, нам нужно освободить выделенную ему память с помощью функции free().

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

ЧТО ТАКОЕ МАССИВ?

Массив – это именованная ячейка памяти. Он используется для хранения одинаковых типов данных (таких как целое число, двойное число, строка, логическое значение и т. д.) фиксированного размера непрерывным образом. Это означает, что по адресу определенного значения/местоположения мы можем узнать адрес других значений, используя некоторые математические вычисления, поскольку данные хранятся вплотную друг к другу.

Мы используем массивы, когда нам нужно хранить большой объем данных. Поэтому вместо того, чтобы создавать разные переменные, мы создаем массив из одной переменной, чтобы избежать беспорядка и путаницы. Например, если мы хотим сохранить, скажем, 5 целочисленных значений, то вместо записи:

мы можем объявить массив следующим образом:

Младший адрес массива содержит первый элемент, который начинается с индекса 0, а старший адрес массива содержит последний элемент, заканчивающийся индексом длины-1.

ОБЪЯВЛЕНИЕ МАССИВА

Существует два способа объявления массива:

  • Статические. Статически размещенные массивы — это массивы, объявленные во время компиляции. Они имеют фиксированную длину и выполняются только в определенном блоке кода, где они объявлены.
    Примечание. Они немного отличаются от массивов, объявленных с помощью спецификатора статического класса хранения.
    Синтаксис объявления статического массива целочисленного типа и длины 10 следующий:
  1. В приведенном ниже коде 10 блоков памяти были выделены массиву целых чисел, и каждое значение массива по умолчанию инициализируется нулем.
  1. В приведенном ниже коде 10 блоков памяти были выделены для целочисленного массива, и каждое значение массива инициализировано предоставленным значением.
    1. В приведенном ниже коде 10 блоков памяти были выделены массиву целых чисел, и первые три значения (от 0 до 2) массива инициализируются указанным значением, а остальные 7 значений (3-9) инициализирован до 0.
    • Динамический: динамические массивы объявляются во время выполнения. Первоначально они объявляются с использованием malloc или calloc для фиксированного размера. Позже их размер можно изменить с помощью realloc, что невозможно в статическом объявлении.
      Примечание. Будьте внимательны и не забывайте освобождать память, выделенную динамически, иначе может произойти утечка памяти и в какой-то момент программа может аварийно завершить работу.
      Синтаксис для объявления динамический массив с последующим изменением размера выглядит следующим образом:

    В приведенном выше коде изначально 6 блоков памяти были выделены для целочисленного массива, и каждое значение массива инициализировалось нулем. Позже с помощью realloc был изменен размер массива и выделено еще 4 блока памяти для целочисленного массива с инициализацией 0 для каждого значения.

    Разница между статическими и динамическими массивами:

    Когда память выделяется для массива путем указания размера во время компиляции, размер массива фиксируется и не может быть изменен во время выполнения. Такие массивы известны как статические массивы.
    С другой стороны, когда память выделяется для массива путем указания размера во время выполнения, размер массива не является постоянным и может быть изменен во время выполнения. Такие массивы известны как динамические массивы и создаются с использованием переменных-указателей и выделенной памяти с помощью функций управления памятью calloc/malloc, а размер изменяется с помощью функции realloc.

    Статические массивы используются только в том случае, если заранее известен объем данных. В тех случаях, когда мы не уверены в своих требованиях к данным, используются динамические массивы.

    При статическом выделении памяти неиспользуемая выделенная память тратится впустую, тогда как при динамическом выделении памяти память выделяется по мере необходимости и, следовательно, минимизирует потери памяти.

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

    Удаление массива означает, что нам нужно освободить память, которая была выделена для массива, чтобы ее можно было использовать для других целей.
    Массивы занимают много места в нашей памяти. Следовательно, чтобы освободить память в конце программы, мы должны удалить/освободить байты памяти, используемые массивом, чтобы предотвратить нерациональное использование памяти.

    Если массив объявлен статически, то нам не нужно удалять массив, так как он удаляется в конце программы/блока, в котором он был объявлен.

    Но если массив объявляется динамически, т.е. с помощью malloc/calloc, то нам нужно освобождать занятое ими место в памяти к концу программы, чтобы программа не падала. Это можно сделать, вызвав метод free и передав массив.
    Когда мы выделяем память динамически, некоторая часть информации сохраняется до или после выделенного блока. free использует эту информацию, чтобы узнать, как была выделена память, а затем освобождает весь блок памяти.
    То же самое делается следующим образом:

    В приведенном выше примере весь массив a передается в качестве аргумента встроенной функции free, которая освобождает память, назначенную массиву a.

    Однако, если мы выделяем память для каждого элемента массива, нам нужно освободить каждый элемент перед удалением массива.

    В приведенном выше коде память, выделенная каждому элементу, удаляется до фактического освобождения указателя массива.

    Из этой статьи на OpenGenus вы должны иметь полное представление об удалении или освобождении массива в C. Наслаждайтесь.

    Массивом называется группа компонентов с одинаковыми типами данных, расположенных в ячейках встроенной памяти. На него можно ссылаться исключительно через индекс к одному идентификатору. Вы можете установить значения массива типа «int» по своему выбору, предопределенные, а также определенные в программе или во время выполнения. Под удалением массива понимается удаление всего массива из программы без изменения кода, последовательности и логики программы.

    Когда мы инициализировали новый массив, накопилось динамическое выделение памяти, которое поместило переменные в память кучи. Это захватывает длинную память, когда вы определяете массив в коде из кучи. Внутри оператора удаления есть возвращаемый тип void, который не возвращает какое-либо значение функции. Delete[] — это оператор, функция которого состоит в удалении массива, созданного новыми выражениями.

    Необходимость удаления объекта

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

    В этой статье давайте обсудим различные подходы к удалению массива из памяти с помощью очень простого метода на C++.

    Удаление пустых объектов массива

    Удаление массивов во всех языках — это единственный момент объекта в коде, который можно было бы сделать в начале программы. Также во время выполнения при использовании оператора с термином «новый» оператор удаляется оператором удаления. С другой стороны, массив объектов удаляется с помощью оператора delete[], после чего не может привести к утечке памяти. Здесь мы используем простой и базовый пример удаления массива с помощью квадратных скобок [], но сначала мы используем предел массива 10, а затем удаляем массив.



    Поскольку массив пуст и в нем нет элементов, мы не отображали массив. Элементы будут показаны на следующем рисунке.

    Удаление объекта массива, имеющего значения

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


    В основной части мы берем переменную «i» цикла и массив с именем «arr» и длиной 5, содержащий элементы от 1 до 5. Затем мы написали цикл «for», чтобы показать элементы массива, чтобы проверить, пуст наш массив или нет. После этого оператор delete[] выполняет свои функции. Вот как наш массив удаляется.


    Здесь легко увидеть элементы массива, который был инициализирован при запуске программы.

    Удаление нескольких массивов

    Наконец, здесь мы объясняем, как удалить два или более массива в одной программе. Переменная, тип данных которой определяется пользователем, содержит фактические данные, а не указывает на данные. Во всех языках программирования указатели также являются переменными, но имеют адреса других дополнительных переменных. Здесь a* — переменная-указатель, а array1 и array2 — массив целых чисел. Строка кода, где a* = array1 получает адрес самого первого компонента массива в переменной a.


    После использования заголовочных файлов мы определяем структуру с переменной «a». В этой структуре мы объявляем две статические функции и передаем аргумент указателя, а также переменную размером с массив. Единственный объект кода создается во время выполнения на C++ с использованием оператора new. В функции мы отображаем наши статические массивы. В основном теле мы берем объект-указатель и два массива с именами array1 и array2 соответственно, которые имеют разные размеры. После этого мы используем оператор удаления [] для удаления массива.


    Здесь мы получаем первый массив с помощью объекта и удаляем его, а затем снова второй массив с помощью объекта и удаляем его.

    Заключение

    В этой статье описаны массив и удаление массивов в языке C++. Мы также обсудили, почему нам нужно удалить массив с помощью нескольких подходов, которые используются для удаления массива в C++. Мы удаляем массив, не имеющий значения, а также добавляем элементы в массив, а затем удаляем его последним с помощью указателя. По этой статье мы понимаем, что мы также можем удалять два или более массива одновременно с помощью объектов.

    Об авторе

    Омар Фарук

    Здравствуйте, читатели! Меня зовут Омар. В последнее десятилетие я пишу технические статьи. Вы можете ознакомиться с моими текстами.

    Читайте также: