Давайте ударим дизассемблер!Это будет отличаться для C и C ++.Как free
работает в C, рассматривается в другом вопросе, и вот как это работает в C ++:
struct T {
~T();
int data;
};
void test(T* p)
{
delete[] p;
}
И давайте запустим компилятор для создания сборки.Вот соответствующие биты, скомпилированные для i386:
movl -4(%edi), %eax
leal (%edi,%eax,4), %esi
cmpl %esi, %edi
je L4
.align 4,0x90
L8:
subl $4, %esi
movl %esi, (%esp)
call L__ZN1TD1Ev$stub
cmpl %esi, %edi
jne L8
. Вы можете увидеть важную часть: перед началом p
хранится целое число, содержащее длину p
, и код затем зацикливаетсянад массивом p
, вызывая деструктор для каждого элемента в массиве.Затем он вызывает delete
, что обычно довольно скучно, потому что он просто вызывает free
(функция C).Таким образом, вы можете увидеть, как C ++ delete
выражается в виде free
.
Деструкторы и исключения: На основе вышеуказанной сборки вы можете заметить, что если деструктор для T
выдает исключение, тогда часть массива p
будет вызывать деструктор, а остальная часть массива - нет.Деструкторы никогда не должны выдавать исключения.
Предупреждение: Это только один из возможных способов, с помощью которого ваш компилятор и среда выполнения могут решить эту проблему.(Здесь деструктор вызывается сгенерированным компилятором кодом, и delete
является частью среды выполнения.) Существует довольно много возможностей для их реализации, и ваш может отличаться.Это также показывает, почему вы всегда должны вызывать правильный оператор, delete[]
или delete
- вызов неправильного оператора вызовет всевозможные проблемы, такие как топание памяти и освобождение недействительных указателей.
О NUL-терминаторах: Единственная причина, по которой NUL-терминаторы являются проблемой, заключается в том, что PyString_AsString
и другие подобные функции вызывают strlen
, чтобы выяснить, какова длина строки.Однако free
не заботится о NUL-терминаторах, вместо этого он отдельно отслеживает длину от исходного вызова malloc
.Для PyString_AsString
(и strdup
и т. Д.) Это не вариант, потому что нет портативного способа получить размер области памяти - malloc
и free
не предоставляют эту функциональность.Кроме того, вы можете передать указатель на PyString_AsString
, который находится в середине блока malloc
или где-то еще целиком.