Foo* set = new Foo[100];
// ...
delete [] set;
Вы не передаете границы массива delete[]
. Но где хранится эта информация? Это стандартизировано?
Foo* set = new Foo[100];
// ...
delete [] set;
Вы не передаете границы массива delete[]
. Но где хранится эта информация? Это стандартизировано?
Ответы:
Когда вы распределяете память в куче, ваш распределитель будет отслеживать, сколько памяти вы выделили. Обычно он хранится в «головном» сегменте непосредственно перед выделенной вам памятью. Таким образом, когда пришло время освободить память, де-распределитель точно знает, сколько памяти освободить.
free
узнать, сколько памяти нужно освободить». Да, размер блока памяти «где-то» хранится malloc
(обычно в самом блоке), так что, как free
знать. Однако new[]
/ delete[]
это другая история. Последние в основном работают поверх malloc
/ free
. new[]
также хранит количество элементов, которые он создал в блоке памяти (независимо от malloc
), чтобы впоследствии delete[]
можно было извлечь и использовать этот номер для вызова надлежащего количества деструкторов.
malloc
) и количество элементов (по new[]
). Обратите внимание, что первое не может быть использовано для вычисления второго, так как в общем случае размер блока памяти может быть больше, чем действительно необходимо для массива запрошенного размера. Также обратите внимание, что счетчик элемента массива необходим только для типов с нетривиальным деструктором. Для типов с тривиальным деструктором счетчик не сохраняется new[]
и, конечно, не восстанавливается delete[]
.
Один из подходов для компиляторов - выделить немного больше памяти и сохранить количество элементов в элементе head.
Пример того, как это можно сделать:
Вот
int* i = new int[4];
Компилятор будет выделять sizeof(int)*5
байты.
int *temp = malloc(sizeof(int)*5)
Будем хранить «4» в первых sizeof(int)
байтах
*temp = 4;
и установить i
i = temp + 1;
Так i
будет указывать на массив из 4 элементов, а не 5.
И удаление
delete[] i;
будет обработан следующим образом:
int *temp = i - 1;
int numbers_of_element = *temp; // = 4
... call destructor for numbers_of_element elements
... that are stored in temp + 1, temp + 2, ... temp + 4 if needed
free (temp)
Информация не стандартизирована. Однако на платформах, над которыми я работал, эта информация хранится в памяти непосредственно перед первым элементом. Поэтому вы можете теоретически получить к нему доступ и осмотреть его, однако это того не стоит.
Также именно поэтому вы должны использовать delete [], когда вы выделяете память с помощью new [], так как версия массива delete знает, что (и где) нужно искать, чтобы освободить нужное количество памяти, и вызывать соответствующее количество деструкторов. для объектов.
В основном это расположено в памяти как:
[info] [mem вы просили ...]
Где информация - это структура, используемая вашим компилятором для хранения объема выделенной памяти, а что нет.
Это зависит от реализации, хотя.
Он определен в стандарте C ++ как специфичный для компилятора. Что означает магию компилятора. Это может сломаться с нетривиальными ограничениями выравнивания по крайней мере на одной основной платформе.
Вы можете думать о возможных реализациях, понимая, что delete[]
это определено только для указателей, возвращаемых new[]
, которые могут не совпадать с указателями, возвращаемыми operator new[]
. Одной из реализаций в дикой природе является сохранение числа массивов в первом int, возвращаемом operator new[]
и new[]
возвращаемое смещение указателя после этого. (Вот почему нетривиальные выравнивания могут нарушаться new[]
.)
Имейте в виду , что operator new[]/operator delete[]
! = new[]/delete[]
.
Плюс, это ортогонально тому, как C знает размер памяти, выделенной malloc
.
Потому что массив, который нужно «удалить», должен был быть создан с помощью единственного использования оператора «new». «Новая» операция должна была поместить эту информацию в кучу. Иначе как дополнительные пользователи new узнают, где заканчивается куча?
Это не стандартизировано. Во время выполнения Microsoft новый оператор использует malloc (), а оператор удаления - free (). Итак, в этой настройке ваш вопрос эквивалентен следующему: Как free () узнает размер блока?
За кулисами происходит некоторая бухгалтерия, то есть во время выполнения Си.
Это более интересная проблема, чем вы думаете на первый взгляд. Этот ответ об одной возможной реализации.
Во-первых, в то время как на каком-то уровне ваша система должна знать, как «освободить» блок памяти, лежащий в основе malloc / free (который обычно вызывают new / delete / new [] / delete []) не всегда точно помнит, сколько памяти Вы просите, он может округляться (например, если вы выше 4К, его часто округляют до следующего блока размером 4К).
Поэтому, даже если бы можно было получить размер блока памяти, это не говорит нам, сколько значений находится в новой [] ed памяти, поскольку оно может быть меньше. Поэтому нам нужно хранить дополнительное целое число, сообщающее нам, сколько существует значений.
ЗА ИСКЛЮЧЕНИЕМ, если конструируемый тип не имеет деструктора, то delete [] не должен делать ничего, кроме освобождения блока памяти, и, следовательно, не должен ничего хранить!