Есть ли опасность при вызове free() или delete вместо delete []?

Возможный дубликат:
(POD) освобождение памяти: delete [] равно удалению?

Удаляет ли delete элементы за пределами первого в массиве?

char *s = new char[n];
delete s;

В этом случае имеет значение, поскольку все элементы s распределены смежно, и не должно быть delete только часть массива?

Для более сложных типов delete вызывает деструктор объектов за пределами первого?

Object *p = new Object[n];
delete p;

Как delete[] вывести число Object за пределы первого, не означает ли это, что он должен знать размер выделенной области памяти? Что, если область памяти была выделена с некоторым выступом по соображениям производительности? Например, можно предположить, что не все распределители обеспечивали детализацию одного байта. Тогда любое конкретное распределение может превышать требуемый размер для каждого элемента целым элементом или более.

Для примитивных типов, таких как char, int, есть ли разница между:

int *p = new int[n];
delete p;
delete[] p;
free p;

За исключением маршрутов, принимаемых соответствующими вызовами через механизм освобождения от отказа deletefree?

Ответ 1

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

Нарушение этого правила может привести к правильной работе по совпадению, но программа может сломаться, как только что-либо изменится - компилятор, среда выполнения, настройки компилятора. Вы никогда не должны полагаться на такое надлежащее функционирование и ожидать этого.

delete[] использует данные службы, специфичные для компилятора, для определения количества элементов. Обычно выделяется более крупный блок при вызове new[], номер сохраняется в начале, а вызывающему абоненту присваивается адрес за сохраненным номером. В любом случае delete[] полагается на блок, выделяемый new[], а не что-либо еще. Если вы соедините что-либо кроме new[] с delete[] или наоборот, вы столкнетесь с поведением undefined.

Ответ 2

Прочтите FAQ: 16.3 Могу ли я освобождать() указатели, выделенные новым? Могу ли я удалить указатели, выделенные с помощью malloc()?

В этом случае имеет значение, поскольку все элементы s распределены смежно, и не удастся удалить только часть массива?

Да, да.

Как удалить [] вывод количества объектов за пределами первого, не означает ли это, что он должен знать размер выделенной области памяти?

Компилятор должен знать. См. FAQ 16.11

Потому что компилятор сохраняет эту информацию.

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

Ответ 3

Да, это опасно!

Не делайте этого!

Это приведет к сбоям в программе или даже к худшему поведению!

Для объектов, выделенных с помощью new, вы ДОЛЖНЫ использовать delete;

Для объектов, выделенных с помощью new [], вы ДОЛЖНЫ использовать delete [];

Для объектов, выделенных с помощью malloc() или calloc(), вы ДОЛЖНЫ использовать free();

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

Ответ 4

Да, есть реальная практическая опасность. Даже детали реализации в стороне, помните, что функции operator new/operator delete и operator new[]/operator delete[] могут быть полностью заменены независимо. По этой причине разумно думать о new/delete, new[]/delete[], malloc/free и т.д. Как о разных, полностью независимых методах распределения памяти, которые не имеют абсолютно ничего общего.

Ответ 5

Удаляет ли освобождение элементов за пределами первого в массиве?

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

Имеет ли значение в вышеприведенном случае видение, поскольку выделяются все элементы s смежно и не удастся удалить только часть массива?

Зависит от того, как память отмечена как свободная. Опять зависит от реализации.

Для более сложных типов удалите вызов деструктора объектов за пределы первого?

Нет. Попробуйте следующее:

#include <cstdio>

class DelTest {
    static int next;
    int i;
public:
    DelTest() : i(next++) { printf("Allocated %d\n", i); }
    ~DelTest(){ printf("Deleted %d\n", i); }
};

int DelTest::next = 0;

int main(){
    DelTest *p = new DelTest[5];
    delete p;
    return 0;
}

Как удалить [] вывести число Объекты за пределами первого, не это означает, что он должен знать размер выделенной области памяти?

Да, размер сохраняется в некотором месте. Где он хранится, зависит от реализации. Например, распределитель может хранить размер в заголовке, предшествующем выделенному адресу.

Что, если область памяти была выделяется с некоторым выступом для производительности? Например, один может предположить, что не все распределители обеспечит гранулярность один байт. Тогда любой конкретный распределение может превышать размер для каждого элемента в целом элемент или больше.

Именно по этой причине возвращенный адрес выполняется для выравнивания по границам слов. "Сверху" можно увидеть с помощью оператора sizeof и также применить к объектам в стеке.

Для примитивных типов, таких как char, int, есть ли разница между...?

Да. malloc и new могут использовать отдельные блоки памяти. Даже если это не так, хорошая практика не предполагать, что они одинаковы.

Ответ 6

Раймонд Чен (разработчик Microsoft) имеет углубленную статью, посвященную масштабированию по сравнению с векторными удалениями и дает некоторое представление о различиях. См:

http://blogs.msdn.com/oldnewthing/archive/2004/02/03/66660.aspx

Ответ 7

Для примитивных типов, таких как char, int, существует какая-либо разница между:

Я бы сказал, что вы получите поведение undefined. Поэтому вы не должны рассчитывать на стабильное поведение. Вы всегда должны использовать новые/удалить, новые []/delete [] и malloc/free пары.

Ответ 8

Это поведение undefined. Следовательно, anser: да, может быть опасность. И невозможно точно предсказать, что вызовет проблемы. Даже если он будет работать один раз, будет ли он работать снова? Это зависит от типа? Количество элементов?

Ответ 9

Хотя может показаться некоторым логическим способом, что вы можете смешивать новые [] и освобождать или удалять вместо delete [], это предполагает предположение о том, что компилятор является довольно упрощенным, т.е. что он всегда будет использовать malloc ( ) для реализации выделения памяти для новых [].

Проблема заключается в том, что если ваш компилятор имеет достаточно умный оптимизатор, он может видеть, что нет никакого "delete []", соответствующего новому [] для созданного вами объекта. Поэтому он может предположить, что он может извлечь память для него из любой точки, включая стек, чтобы сохранить стоимость вызова реального malloc() для нового []. Затем, когда вы пытаетесь вызвать free() или неправильный вид удаления на нем, это может сильно сработать.

Ответ 10

Шаг 1: what-is-the-difference-between-new-delete-and-malloc-free

Вы смотрите только на то, что видите на стороне разработчика.
Что вы не рассматриваете, так это то, как std lib управляет памятью.

Первое отличие состоит в том, что new и malloc выделяют memroy из двух разных областей памяти (New из FreeStore и malloc из Heap (не сосредотачивайтесь на именах, они оба в основном кучи, это только официальные названия из стандарта )). Если вы выделяете из одного и деблокируете другой, вы испортите структуры данных, используемые для управления памятью (нет гарантии, что они будут использовать ту же структуру для управления памятью).

Когда вы выделяете такой блок:

int*   x= new int; // 0x32

Память Может выглядеть так: Вероятно, это не так, потому что я сделал это, не подумав об этом.

Memory   Value      Comment
0x08     0x40       // Chunk Size  
0x16     0x10000008 // Free list for Chunk size 40
0x24     0x08       // Block Size
0x32     ??         // Address returned by New.
0x40     0x08       // Pointer back to head block.
0x48     0x0x32     // Link to next item in a chain of somthing.

Дело в том, что в выделенном блоке имеется гораздо больше информации, чем только вы выделили для управления памятью.

В стандарте не указывается, как это делается, потому что (в стиле C/С++) они не захотели использовать возможности компилятора/библиотеки для реализации наиболее эффективного метода управления памятью для архитектуры.

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

Если вы действительно анализируете различия в распределении памяти между приложениями C и С++, вы обнаружите, что они очень разные. И, следовательно, нецелесообразно использовать совершенно разные методы управления памятью для оптимизации типа приложения. Это еще одна причина, чтобы предпочесть новый над malloc() в С++, поскольку он, вероятно, будет более эффективным (более важная причина, хотя всегда будет заключаться в уменьшении сложности (IMO)).