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 объекта, и вы в конечном итоге пытаетесь освободить страницу, которая меньше, чем начальный выделенный размер.
Нижняя линия:
удалить [] для нового [] и удалить для нового!
Работает каждый раз!