Почему для массивов существуют специальные функции создания и удаления?

StackOverflow https://stackoverflow.com/questions/659270

Вопрос

Что плохого в использовании delete вместо delete[]?

Происходит ли что-то особенное в процессе выделения и освобождения массивов?

Почему это будет отличаться от malloc и бесплатно?

Это было полезно?

Решение

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

С malloc и free ситуация проще.Существует только одна функция, которая освобождает выделяемые вами данные, также не существует концепции вызова деструктора.Путаница возникает только потому, что delete[] и удалить похожие.На самом деле это две совершенно разные функции.

Использование удаления не приведет к вызову правильной функции для удаления памяти.Он должен позвонить delete[](void*) но вместо этого он вызывает delete(void*).По этой причине вы не можете полагаться на использование delete для памяти, выделенной с помощью new[]

См. этот FAQ по C++.

[16.13] Могу ли я оставить [] При удалении массива какого-то встроенного типа (char, int и т. Д.)?

Нет!

Иногда программисты думают, что [] в delete[] p существует только поэтому компилятор назовет соответствующие деструкторы для всех элементов в массиве.Из-за этого рассуждения они предполагают, что множество встроенных типов, таких как char или int возможно deleteг без [].Например, они предполагают, что следующее является действительным кодом:

void userCode(int n)  {
    char* p = new char[n];
    ...
    delete p; // ← ERROR! Should be delete[] p !
}

Но приведенный выше код неверен, и он может вызвать катастрофу во время выполнения.В частности, код, который требуется delete p является operator delete(void*), но код, который требуется delete[] p является operator delete[](void*).Поведение по умолчанию для последнего состоит в том, чтобы вызвать первое, но пользователям разрешено заменить последнее другим поведением (в этом случае они обычно также заменяют соответствующий новый код в операторе new[](size_t)).Если они заменили delete[] Код, так что он не был совместимы с кодом Delete, и вы позвонили в неправильный (т.е., если вы сказали delete p скорее, чем delete[] p), вы можете получить катастрофу во время выполнения.

Почему delete[] существуют изначально?

Делаете ли вы x или y:

 char * x = new char[100]; 
 char * y = new char;

Оба хранятся в char * типизированные переменные.

Я думаю, что причина решения delete, и delete[] сопровождается длинным списком решений, которые способствуют повышению эффективности C++.Это сделано для того, чтобы не существовало принудительной цены на поиск того, сколько данных необходимо удалить для обычной операции удаления.

Имея 2 new и new[] кажется логичным иметь delete и delete[] во всяком случае для симметрии.

Другие советы

Разница в том, что delete удалит только весь диапазон памяти, но вызовет деструктор только для 1 объекта. delete[] удалит память и вызовет деструктор для каждого объекта. Если вы не используете new[] для массивов, это только вопрос времени, когда вы внесете утечку ресурсов в свое приложение.

РЕДАКТИРОВАТЬ Обновить

В соответствии со стандартом передача объекта, выделенного с помощью <=> на <=>, не определена. Поведение вероятного заключается в том, что оно будет действовать так, как я описал.

Страуструп рассказывает о причинах разделения new/new[] и delete/Операторы delete[]` в разделе «Проектирование и эволюция C++» в разделах с 10.3 по 10.5.1:

  • 10.3 Распределение массива - обсуждается, что им нужен способ, позволяющий выделять массивы объектов с использованием схемы, отдельной от выделения отдельных объектов (т. е. выделения массивов из отдельного хранилища).Добавление версий массива new и delete было решение для этого;
  • 10.5.1 Освобождение массивов - обсуждается проблема с освобождением массивов с использованием только одного delete заключается в том, что необходимо больше информации, чем просто указатель, чтобы определить, указывает ли указатель на первый элемент массива или он просто указывает на один объект.Вместо «усложнения обычного случая выделения и освобождения отдельных объектов», delete[] Оператор используется для обработки массивов.Это соответствует общей философии проектирования C++: «не платите за то, чем не пользуетесь».

Было ли это решение ошибкой или нет, вопрос спорный – у того и другого есть веские аргументы, но мы имеем то, что имеем.

Причина этого требования историческая и потому что new type и new type [size] возвращают разные вещи, которые нужно очистить по-разному.

Рассмотрим этот код

Foo* oneEntry = new Foo;
Foo* tenEntries = new Foo[10];

Они оба возвращают указатель Foo *, разница в том, что второй вызов приведет к тому, что конструктор Foo будет вызываться в 10 раз, а объем памяти примерно в 10 раз больше.

Итак, теперь вы хотите освободить свои объекты.

Для одного объекта вы бы назвали delete - например, delete oneEntry. Это вызывает деструктор объектов и освобождает память.

Но вот в чем проблема - oneEntry и tenEntries являются просто указателями Foo. Компилятор не знает, указывают ли они на один, десять или тысячу элементов.

Когда вы используете специальный синтаксис delete []. Это сообщает компилятору &, Это массив объектов, вычисляет количество и затем уничтожает их все & Quot;.

Что действительно происходит, так это то, что для <=> компилятор тайно хранит «размер» в другом месте. Когда вы вызываете delete [], он знает, что это секретное значение существует, поэтому он может узнать, сколько объектов находится в этом блоке памяти, и уничтожить их.

Тогда вы можете задать вопрос ", почему компилятор не всегда сохраняет размер? "

Это отличный вопрос, и он восходит к ранним временам C ++. Было желание, чтобы для встроенных типов (char, int, float и т. Д.) Для C ++ было бы допустимо следующее:

int* ptr = new int;
free(ptr);

int* ptr = (int*)malloc(sizeof(int) * someSize);
delete ptr;

Причиной этого было ожидание того, что люди будут предоставлять библиотеки, которые возвращали динамически распределенную память, и пользователи этих библиотек не смогут узнать, использовать ли free / delete.

Это стремление к совместимости означало, что размер массива не может быть сохранен как часть самого массива и должен был храниться в другом месте. Из-за этих накладных расходов (и помните, это было еще в начале 80-х годов) было решено вести эту книгу только для массивов, а не для отдельных элементов. Таким образом, массивам нужен специальный синтаксис удаления, который ищет это значение.

Причина, по которой у malloc / free такой проблемы нет, заключается в том, что они просто работают с блоками памяти и не должны беспокоиться о вызове конструкторов / деструкторов.

Что касается &, почему " в заголовке: одна из целей разработки C ++ заключалась в том, чтобы не было никаких скрытых затрат. C ++ также был разработан в то время, когда каждый байт памяти все еще имел значение гораздо больше, чем сегодня. Дизайнеры языка также любят ортогональность: если вы выделяете память с помощью new[] (вместо new), вы должны освободить ее с помощью delete[].

Я не думаю, что есть техническая причина, по которой delete не удалось вставить "!", я - массив " пометьте в заголовке блока памяти <=> (не более <=>), чтобы посмотреть позже.

new и delete отличаются от malloc и free тем, что <=> и <=> только выделяют и освобождают память; они не называют ctors или dtors.

Когда вы используете new[] для выделения массива, вы фактически указываете C ++ размер массива. Когда вы используете malloc, вы вместо этого сообщаете, сколько памяти выделено. В первом случае освобождение на основе размера массива не имеет смысла. В этом случае это так. Но поскольку нет разницы между указателем для массива и для одного объекта, необходима отдельная функция.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top