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


136

В чем разница между deleteи delete[]операторы в C ++?


Вы можете найти этот вопрос уместным stackoverflow.com/questions/1913343/…
sharptooth

7
Проблемы с delete и delete [] - одна из причин, почему мне нравятся умные указатели и использование 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 в массиве new [] примитивных типов, таких как int или char (без конструктора / деструктора), также к неопределенному поведению. Кажется, что размер массива нигде не сохраняется при использовании примитивных типов.
thomiel 06

21
Если стандарт не определяет, что происходит, когда это делается, это по определению «неопределенное поведение», даже если ваш компилятор детерминированно делает то, что вы хотите. Другой компилятор может делать что-то совершенно другое.
Роб К

Я сделал эту ошибку, когда у меня был массив строк C, например char ** strArray. Если у вас есть такой массив, как у меня, вам нужно выполнить итерацию по массиву и удалить / освободить каждый элемент, а затем удалить / освободить сам strArray. Использование "delete []" в имеющемся у меня массиве не работает, поскольку (как указано в приведенных выше комментариях и ответах) ОНО ВЫЗЫВАЕТ ДЕСТРУКТОРЫ, фактически не освобождает каждый слот.
Katianie

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

Это базовое использование шаблона allocate / DE-allocate в 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 объекта»
Don Larynx

1
Как добиться того же в C?
Dogus Ural

@DogusUral Почему? В C нет деструкторов, поэтому вам нужно только free()то и это. Если вы используете шаблон псевдодеструктора, вы должны вызывать его один раз для каждого объекта, используя forцикл.
Котаускас

@DonLarynx, правильное отличие состоит в том, что их смешивание приводит к некорректной программе. Реализация может знать, сколько объектов разрушить, а может и не знать . Разрешено узнать, что это был неправильный вызов, и прервать программу, сообщив вам, в чем проблема.
Калет

6

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

Объекты, созданные с помощью, newобязательно должны быть уничтожены с помощью delete, а массивы, созданные с помощью, new[]должны быть удалены с помощью delete[].


2

Когда я задал этот вопрос, мой реальный вопрос был: «Есть ли разница между ними? Разве среда выполнения не должна хранить информацию о размере массива, и поэтому она не сможет определить, какой из них мы имеем в виду?» Этот вопрос не встречается в «связанных вопросах», поэтому, чтобы помочь таким, как я, вот ответ на него: «зачем нам вообще нужен оператор delete []?»


Спасибо, что вернулись и
вставили

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.