#c #arrays #multidimensional-array #stl
#c #массивы #многомерный массив #stl
Вопрос:
Я пытаюсь избежать нехватки памяти, и мне нужно понять, нужно ли мне устанавливать nullpointer
для моего многомерного динамического массива после удаления массива. Вот мой код.
int*** arr = new int** [lists];
for (int i = 0; i < lists; i )
{
arr[i] = new int* [row];
for (int r = 0; r < row; r )
{
arr[i][r] = new int[col];
}
}
for (int i = 0; i < lists; i )
{
for (int r = 0; r < row; r )
{
for (int z = 0; z < col; z )
{
arr[i][r][z] = rand() % 100;
}
}
}
for (int i = 0; i < lists; i )
{
for (int r = 0; r < row; r )
{
delete[] arr[i][r];
}
delete[] arr[i];
}
delete[] arr;
arr = nullptr;
Комментарии:
1. Все, что было
new
отредактировано, должно бытьdelete
разделено.2. «Я пытаюсь избежать утечки памяти» , поэтому используйте интеллектуальный указатель и / или контейнеры. избегайте необработанных указателей-владельцев.
3. Нет, вам не нужно
arr = nullptr;
, чтобы избежать утечек памяти. Единственная причина установить для него значениеnullptr
— это если вы по какой-то причине проверите его позже (if(arr) ...
).4. В этом нет необходимости , утечки памяти не будет, если вы не обнуляете указатель, но оставляете его в «зависшем» состоянии. Если вы никогда больше не используете его, все в порядке. Если возможно, что вы будете использовать его снова, лучше всего установить для него значение
nullptr
.5. Не будьте трехзвездочным программистом .
Ответ №1:
Необходимо ли обнулять ваши указатели после удаления многомерного динамического массива
Это зависит. Иногда это так, иногда нет.
Когда вам нужно проверить, есть ли у вас все еще действительный указатель, вы должны присвоить недопустимому указателю значение null, потому что нулевой указатель — это единственный недопустимый указатель, который вы можете проверить. Ваш пример не демонстрирует, что вам нужно было бы это делать.
Довольно часто delete
используется в месте, где срок службы указателя подходит к концу, и в этом случае совершенно излишне устанавливать для него значение null.
P.S. Не используйте владение голыми указателями, подобными этому. Используйте контейнеры RAII, такие как std::vector
или, по крайней мере, интеллектуальные указатели.
Ответ №2:
Утечки памяти в вашем случае не произойдет , но для хорошей практики вам нужно обнулить свой указатель после удаления этого указателя , в противном случае, если вы позже разыменуете ту же переменную, ваша программа будет иметь неопределенное поведение
может возникнуть «ошибка необработанного исключения».
if(arr)
также не помогает в таком случае.
поэтому используйте нулевую проверку каждого указателя перед доступом к указателю
Комментарии:
1. » в противном случае позже, если вы получите доступ к той же переменной … » — Должно быть: «в противном случае, если вы позже разыменуете ту же переменную, ваша программа будет иметь неопределенное поведение».
2. У вас будет неопределенное поведение, независимо от того, установили вы его или нет
arr=nullptr
. Настройкаarr=nullptr
просто облегчает отладку таких незаконных обращений.3. «Хорошая практика, вам нужно обнулять свой указатель после удаления этого указателя» — я сижу по другую сторону баррикад в этом вопросе; лично я думаю, что это приводит к неаккуратному кодированию и маскировке ошибок, которые все еще остаются ошибками.
Ответ №3:
На самом деле это всего лишь вопрос гигиены кода. Я думаю, что основное преимущество настройки arr = nullptr
после удаления заключается в том, что вы можете затем безопасно delete arr[]
в любое более позднее время, не беспокоясь. Это также упрощает обнаружение ошибок, если вы пытаетесь ссылаться на удаленный массив.
Так что это не обязательно, но это то, что я лично делаю как само собой разумеющееся.
Ответ №4:
Используйте SmartPointers, чтобы избежать проблем с утечкой памяти.
Нет, вам не нужно устанавливать переменной Pointer значение «NULL», программа будет работать без проблем.
Установка значения null может служить дополнительной защитой для предотвращения использования переменной по ошибке.
————————
Оператор new резервирует пространство, чтобы при любом новом выделении памяти или для внутренних операций компилятор не занимал эти выделенные ячейки памяти.
Оператор Delete просто отменяет эти оговорки. Ссылочная переменная по-прежнему имеет адрес ячейки памяти, и вы можете получить к ней доступ, но теперь она может быть изменена компилятором в любое время.
Содержимое переменной Pointer до и после операции удаления.
int *a;
cout<<"before memory allocation a= "<<a<<endl;
a= new int[10];
a[0]= 1; a[7]=2;
cout<<"After memory allocation but Before Delete"<<endl;
cout<<"a="<<a<<"ta[0]="<<a[0]<<"ta[7]="<<a[7]<<"ta[22]="<<a[22]<<endl;
cout<<"sizeof(a)="<<sizeof(a)<<"tsizeof(a[7])="<<sizeof(a[7])<<"tsizeof(a[22])="<<sizeof(a[22])<<endl;
delete[] a;
cout<<"After Delete"<<endl;
cout<<"a="<<a<<"ta[0]="<<a[0]<<"ta[7]="<<a[7]<<"ta[22]="<<a[22]<<endl;
cout<<"sizeof(a)="<<sizeof(a)<<"tsizeof(a[7])="<<sizeof(a[7])<<"tsizeof(a[22])="<<sizeof(a[22])<<endl;
return 0;
Результат:
before memory allocation a= 0x40ed39
Before Delete
a=0x9a1550 a[0]=1 a[7]=2 a[22]=1316552972
sizeof(a)=8 sizeof(a[7])=4 sizeof(a[22])=4
After Delete
a=0x9a1550 a[0]=10099280 a[7]=2 a[22]=1316552972
sizeof(a)=8 sizeof(a[7])=4 sizeof(a[22])=4