оператори 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.