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

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

Есть ли что-то особенное в обложках для выделения и освобождения массивов?

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

Ответ 1

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

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

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

См. часто задаваемые вопросы по С++

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

Нет!

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

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 p скорее чем delete[] p), вы могли бы с бедой во время выполнения.

Почему delete[] существует в первую очередь?

Выполняете ли вы x или y:

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

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

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

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

Ответ 2

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

ИЗМЕНИТЬ Обновить

В соответствии со стандартом передача объекта, выделенного с помощью new[] to delete, составляет undefined. Поведение Вероятно заключается в том, что он будет действовать, как я описал.

Ответ 3

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

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

ли это решение было ошибкой или не является дискуссионным. - в любом случае имеет хорошие аргументы, но мы имеем то, что имеем

Ответ 4

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

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

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

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

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

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

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

При использовании специального синтаксиса delete []. Это говорит компилятору: "Это массив объектов, вычисляйте счет, а затем уничтожайте их все".

Что действительно происходит, так это то, что для new type [size] компилятор тайно хранит "размер" где-то в другом месте. Когда вы вызываете delete [], он знает, что это секретное значение существует, чтобы он мог узнать, сколько объектов находится в этом блоке памяти и уничтожить их.

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

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

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

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

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

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

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

Ответ 5

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

Я не думаю, что существует какая-либо техническая причина, по которой new[] не может вставить флаг "Я - массив" в заголовке блока памяти для delete (не более delete[]), чтобы посмотреть на позже.

Ответ 6

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

Ответ 7

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