Мне сложно найти ответ, как конкретно выполнить эту операцию должным образом.
Я хотел бы лучше понять различные способы удаления новой памяти, выделенной в куче, особенно в случае двумерного массива.
Для моего примера: У меня есть массив размером 5 в стеке, состоящий из указателей int (int * d [5]). Я инициализирую каждый из этих указателей int в цикле, чтобы создать и указать на массив int размером 8 в куче (d [i] = new int [8]). По сути, я создал двумерный массив (d [j] [k]).
У меня вопрос: каков синтаксис для удаления только отдельных массивов (int [8]) в куче?
В настоящее время у меня это так, но при отладке кажется, что массивы не освобождаются после его выполнения ...
для (int i = 0; i <5; ++ i) удалить d [i];
Что должно быть: «удалить [] d [i]» или просто «удалить [] d» или какой-то другой вариант? Кроме того, есть ли способ удалить отдельные элементы массивов int [8]? Если бы кто-нибудь мог кратко объяснить синтаксис и их различия, это было бы очень полезно. Спасибо!
Если вы распределили массивы через d[i] = new int[8]
, то вы должны удалить их через delete[] d[i]
. Невозможно освободить отдельные элементы такого массива, не освободив целиком.
Понятно, спасибо. Я пробовал удалить [] d [i]; но вроде бы не получилось. В отладчике (gdb) он все еще показывает, что массивы int [8] существуют после удаления и содержат все значения, которыми я их инициализировал? Я не знаю, что делать ...
@MajinMilad Тот факт, что отладчик показывает, что память не повреждена, не означает, что вам разрешен программный доступ к ней. Для этого вызовет неопределенное поведение.
@MajinMilad Когда вы освобождаете память, это просто означает, что она помечена как свободная для использования в дальнейшем. Он не перезаписывается сразу.
Оооо, хорошо, это имеет большой смысл. Значит, он помечен как свободный для дальнейшего распределения, но все еще может содержать свои старые значения до перераспределения и перезаписи?
Точно. В этом отношении это похоже на удаленные файлы на жестком диске.
Кроме того, значит, он работает? Что правильно "удалить [] d [i]" или "удалить d [i]"
Первое, как и сказано в моем ответе.
@MajinMilad, если ваша проблема решена, поставьте галочку, чтобы отметить ответ как принятый.
вы упомянули, что распределяете внутренние массивы внутри цикла. который, как мне кажется, выглядит примерно так.
int*d[2];
for (int i = 0; i < 2; i++)
{
d[i] = new int[3];
}
Обратите внимание, что d[2]
содержит только указатели на массивы.
поэтому, чтобы удалить этот массив, вам нужно перебрать каждый набор указателей массива
и вызовите delete [] d [i];
for (int i = 0; i < 2; i++)
{
delete[] d[i];
}
В качестве дополнительного примечания было бы очень полезно знать, как ваша IDE пытается обнаружить повреждения памяти.
например в визуальной студии (в режиме DEBUG)
Имея это в виду, давайте посмотрим, сможем ли мы понять, что делает среда IDE при выполнении приведенного выше кода.
Когда d-массив объявлен как int*d[2];
, структура памяти выглядит следующим образом;
обратите внимание, что массив d имеет два элемента, но ни один из них не имеет начальных значений, поэтому они назначаются 0xCC
давайте посмотрим, что произойдет после того, как мы сделаем d[i] = new int[3];
обратите внимание, что теперь массив d состоит из двух элементов, каждый из которых содержит массив типа int. значения, которые вы видите, являются адресами указателей на массив, для которого мы выделили память.
поскольку мы знаем адреса, мы можем заглянуть в память и увидеть, что там происходит при выделении и удалении каждого массива.
например, после того, как мы выделим наш второй массив int в цикле for, расположение памяти будет выглядеть примерно так;
обратите внимание, что весь элемент массива имеет 0xCD
с окончанием на 0xFD
. Это будет указывать в моей среде IDE, что память выделена и окружена ограждением.
Давайте посмотрим, что произойдет, когда d[2]
будет удален.
Понятно, спасибо. "delete [] d [i]" освободит память в куче (int [3]), на которую указывает d [i], правильно? Он не удаляет фактический указатель d [i]
@MajinMilad, это правильно. думайте об этом так. указатель - это переменная, которая просто содержит значение адреса объекта, на который он должен указывать. конечно, это может быть нулевой ptr, если он ни на что не указывает, или недействительный указатель, если он указывает на уже удаленный объект.
@MajinMilad, вы можете найти больше ответа здесь stackoverflow.com/questions/23621677/…
извините, но у меня есть класс MC
с двумя членами, объект enum
и char
. У меня есть указатель на этот класс в виде карты, и я использую MC* map = new MC[1050]
. Я отношусь к нему как к 2d-массиву, и он работает нормально, пока игрок не умрет, игра не закончится и не пришло время для карты быть delete
ed, delete[] map
выкидывает Invalid address specified to RtlValidateHeap([some address], [some address])
, и программа вылетает, какие-нибудь предложения?
std::vector<std::vector<int>>
решает почти все проблемы, с которыми вы обязательно столкнетесь, включая возможность последовательного удаления (хотя и потенциально дорого). RAII - это то, что на ужин.