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


136

У чому різниця між deleteі delete[]оператори в C ++?


Ви можете знайти це питання відповідний stackoverflow.com/questions/1913343 / ...
— Sharptooth

7
Проблеми з видаленням та видаленням [] є однією з причин, чому мені подобаються розумні покажчики та використання vector<>замість масиву, коли я можу.
— Девід Торнлі


@DavidThornley Якщо ви використовуєте смарт-покажчики, вам все одно потрібно знати різницю в тому сенсі, що ви все ще повинні знати, щоб не писати, наприклад std::unique_ptr<int>(new int[3]), тому що він буде викликати регулярний deleteмасив, який є невизначеною поведінкою. Замість цього вам потрібно використовуватиstd::unique_ptr<int[]>
— Артур Такка

Відповіді:


151

deleteОператор звільняє пам'ять і викликає деструктор для одного об'єкта , створеного з new.

delete []Оператор звільняє пам'ять і виклики деструкторів для масиву об'єктів , створених з new [].

Використання deleteвказівника, повернутого new []або delete []вказівника, повернутого newрезультатами невизначеної поведінки.


3
Цікаво, якщо використання delete на новому [] масиві примітивних типів, таких як int або char (не конструктор / деструктор), обов'язково призводить і до невизначеної поведінки. Здається, розмір масиву ніде не зберігається при використанні примітивних типів.
— thomiel

21
Якщо стандарт не визначає, що відбувається, коли це робиться, це за визначенням "невизначена поведінка", навіть якщо ваш компілятор детерміновано робить те, що ви хотіли б зробити. Інший компілятор може зробити щось зовсім інше.
— Роб К

Я зробив цю помилку, коли мав масив C рядків типу "char ** strArray". Якщо у вас є масив, як у мене, вам потрібно пройти ітерацію через масив і видалити / звільнити кожен елемент, а потім видалити / звільнити сам strArray. Використання "delete []" у масиві, який я маю, не працює, оскільки (як вказували вищевказані коментарі та відповіді), ЦЕ ЗАВДАЄ ДЕСТРУКТОРІ, він фактично не звільняє кожен слот.
— Катяні

88

delete[]Оператор використовується для видалення масивів. deleteОператор використовується для видалення об'єктів без масивів. Він викликає operator delete[]і operator deleteфункціонує відповідно, щоб видалити пам'ять, яку об'єкт масиву або не масив займав після (зрештою) виклику деструкторів для елементів масиву або об'єкта, що не є масивом.

Далі показано відносини:

typedef int array_type[1];

// create and destroy a int[1]
array_type *a = new array_type;
delete [] a;

// create and destroy an int
int *b = new int;
delete b;

// create and destroy an int[1]
int *c = new int[1];
delete[] c;

// create and destroy an int[1][2]
int (*d)[2] = new int[1][2];
delete [] d;

Для того, newщо створює масив (таким чином, new type[]або newзастосовується до конструкції типу масиву), Стандарт шукає operator new[]клас типу елемента масиву або в глобальній області і передає потрібний обсяг пам'яті. Він може вимагати більше, ніж N * sizeof(ElementType)якщо хоче (наприклад, зберігати кількість елементів, тому пізніше при видаленні знає, скільки викликів деструктора виконано). Якщо клас оголошує, operator new[]що додатковий об'єм пам'яті приймає інший size_t, цей другий параметр отримає кількість виділених елементів - він може використовувати це для будь-яких цілей, які він захоче (налагодження тощо).

Для того, newщо створює об'єкт без масиву, він буде шукати operator newв класі елемента або в глобальному масштабі. Він передає потрібний обсяг пам'яті (точно sizeof(T)завжди).

Для цього delete[], він вивчає тип класу елементів масиву та викликає їх деструктори. Використовувана operator delete[]функція - це в класі типу елемента, або якщо такої немає, то в глобальній області застосування.

Для delete, якщо переданий покажчик є базовим класом типу фактичного об'єкта, базовий клас повинен мати віртуальний деструктор (інакше поведінка не визначена). Якщо це не базовий клас, то викликається деструктор цього класу і використовується ін operator deleteв цьому класі або глобальному operator delete. Якщо базовий клас був переданий, то викликається деструктор фактичного типу об'єкта, і використовується operator deleteзнайдений у цьому класі, або якщо його немає, operator deleteназивається глобальним . Якщо operator deleteу класі є другий параметр типу size_t, він отримає кількість елементів, які потрібно розмістити.


18

Це основне використання шаблону виділення / DE-виділення в c ++ malloc/ free, new/ delete, new[]/delete[]

Нам потрібно використовувати їх відповідно. Але я хотів би додати саме це розуміння для різниці між deleteтаdelete[]

1) deleteвикористовується для виділення пам'яті, виділеної для одного об'єкта

2) delete[]використовується для виділення пам'яті, виділеної для масиву об'єктів

class ABC{}

ABC *ptr = new ABC[100]

коли ми говоримо new ABC[100], компілятор може отримати інформацію про те, скільки об'єктів потрібно виділити (тут це 100) і зателефонує конструктору для кожного із створених об'єктів

але відповідно, якщо ми просто використаємо delete ptrдля цього випадку, компілятор не буде знати, скільки об’єктів, на які ptrвказує, і в кінцевому підсумку викличе деструктор і видалить пам'ять лише для 1 об’єкта (залишивши виклик деструкторів і переміщення решти 99 об'єктів). Значить, відбудеться витік пам'яті.

тому нам потрібно використовувати delete [] ptrв цьому випадку.


3
Це має бути правильна відповідь. Жоден з інших відповідей не згадує різну різницю: "але відповідно, якщо ми просто використовуємо delete ptr для цього випадку, компілятор не буде знати, скільки об'єктів, на які вказує ptr, і в кінцевому підсумку викликає деструктор і видаляє пам'ять лише для 1 об'єкта"
— Дон Ларінкс

1
Як ми можемо досягти одного і того ж в C?
— Dogus Ural

@DogusUral Чому? У С деструкторів немає, тож ви просто free()це і те. Якщо ви використовуєте шаблон псевдодеструктора, вам доведеться викликати його один раз для кожного об'єкта, використовуючи forцикл.
— Kotauskas

@DonLarynx правильна різниця полягає в тому, що змішування їх призводить до неправильно сформованої програми. Реалізація може знати, скільки об’єктів зруйнувати, а може й не . Дозволяється знати, що це називалося неправильним, і переривати програму, щоб сказати, де проблема.
— Калет

6

Оператори deleteі delete []використовуються відповідно для знищення об'єктів , створених з допомогою newі new[], повертаючись до виділеної пам'яті залишається доступним для менеджера пам'яті компілятора.

Об'єкти, створені за допомогою, newобов'язково повинні бути знищені delete, а масиви, створені за допомогою, new[]повинні бути видалені за допомогою delete[].


2

Коли я задав це запитання, моє справжнє запитання було: "Чи є різниця між двома? Чи час виконання не повинен зберігати інформацію про розмір масиву, і тому він не зможе сказати, про який ми маємо на увазі?" Це запитання не відображається в "пов'язаних питаннях", тому просто для вирішення таких, як я, ось відповідь на це: "навіщо нам навіть потрібен оператор delete []?"


Дякуємо, що повернулися і поставили це.
— Ziffusion

0

deleteвикористовується для одного єдиного вказівника і delete[]використовується для видалення масиву через вказівник. Це може допомогти вам зрозуміти краще.


-6

Ну .. можливо я думаю, що це просто для явного. Оператор deleteі оператор delete[]відрізняються, але deleteоператор також може випускати масив.

test* a = new test[100];
delete a;

І вже перевірений цей код не має витоку пам’яті.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.