C++ delete[] против delete в массиве массивов

Я знаю, что если я использую new[], я должен удалить [], но это мое сомнение:

Декларация:

char **data; // This will be a bi-dimensional array

Построить:

data = new char*[10];
for (int i=0; i<10; ++i) 
{
  data[i] = new char[128];
}

уничтожить:

for (int i=0; i<10; ++i) 
{
  delete data[i]; // <--- delete or delete[] ???
}
delete[] data;

Еще один случай, когда у меня есть массив объектов:

Декларация:

myClass **object;

Построить:

object = new myClass*[10];
for (int i=0; i<10; ++i) 
{
  object[i] = new myClass();
}

уничтожить:

for (int i=0; i<10; ++i) 
{
  delete object[i]; // <--- this object[] is not an array, right?
}
delete[] object; // <--- Is this correct?

3 ответа

Вы в основном ответили на свой вопрос. поскольку data[i] это массив, вам нужно delete[], object[i] был выделен с new так что вы бы delete Это. Поскольку и объект, и данные являются массивами, вам необходимо delete[] их.

Первое измерение вашего указателя data это массив. Второе измерение также является массивом. Поэтому вы должны использовать delete[] правильно освободить память, зарезервированную от вашего new[],

Для вашего объекта первое измерение было выделено с помощью new, Так что вы должны использовать delete, Тогда используйте delete[] на object потому что это массив.

Упомянутая вами мнемоника (delete [] для new [] и delete для new) является хорошей практикой и должна применяться в обязательном порядке.

Однако существует огромная разница между delete и delete [], когда речь идет о базовых типах (int, char, void* и т. Д.) И классах.

Разница между new и malloc заключается в том, что один вызывает конструктор, а другой нет. То же самое происходит с delete и free, когда дело доходит до деструктора.

В вашем примере вы дали две ситуации: одна, когда выделен массив простого типа, а другая - с массивом выделенных объектов.

Поведение отличается.

Для простого типа delete и delete [] приведут к одинаковому результату.

Причина? в общем, вы выделили блок из 10 указателей на символ *, поэтому удалить его не составит труда (выделенная память будет освобождена).

Другими словами, если у вас есть

 char* a = new char[100];

затем

 delete a;

а также

 delete[] a;

выдаст те же результаты (обратите внимание, что вы использовали новый []);

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

Давайте возьмем следующий класс:

class SimpleClass
{
   public:
         SimpleClass(){printf("constructed");
         ~SimpleClass()(printf("destructed");
}

и следующий код:

SimpleClass* arr1 = new SimpleClass[5];
SimpleClass* arr2 = new SimpleClass[5];
char* arr3 = new char[5];
char* arr4 = new char[5];

delete[] arr4;
delete arr3;
delete[] arr2;
delete arr1; //notice the surprise ?

Запустите приведенный выше код (если можете) в Visual Studio и откройте средство просмотра памяти. Вы увидите, что память, выделенная в ptrs arr4 и arr3, правильно аннулирована, то же самое для arr2.

Однако при попытке удалить arr1 без вызова [] вы получите ошибку SigSev.

Зачем?

Потому что в случае arr2 у вас есть массив выделенных объектов, а оператор delete [] означает "пройти через каждый деструктор из массива"".

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

Нижняя линия:

удалить [] для нового [] и удалить для нового!

Работает каждый раз!

Другие вопросы по тегам