; освобождать особо нечего)
; таким образом, следующая функция – именно деструктор, а не что-нибудь еще
push 1
; количество байт для освобождения (необходимо для delete)
mov ecx, esi
; готовим указатель this
call __destructor
; вызываем деструктор
loc_0_401070: ; CODE XREF: main+25j
pop esi
retn
main endp
__destructor proc near ; CODE XREF: main+2Bp
; функция деструктора. Обратите внимание, что деструктор обычно вызывается
; из той же функции, что и delete (хотя так бывает и не всегда, но очень часто)
arg_0 = byte ptr 8
push ebp
mov ebp, esp
push esi
mov esi, ecx
call Destructor
; вызываем функцию деструктора, определенную пользователем
test [ebp+arg_0], 1
jz short loc_0_40109A
push esi
call ??3@YAXPAX@Z ; operator delete(void *)
add esp, 4
; освобождаем память, ранее выделенную объекту
loc_0_40109A: ; CODE XREF: __destructor+Fj
mov eax, esi
pop esi
pop ebp
retn 4
__destructor endp
Листинг 39
::объекты в автоматической памяти или когда конструктор/деструктор идентифицировать невозможно. Если объект размещается в стеке (автоматической памяти), то никаких проверок успешности ее выделения не выполняется и вызов конструктора становится неотличим от вызова остальных функций. Аналогичная ситуация и с деструктором – стековая память автоматически освобождается по завершению функции, а вместе с ней умирает и сам объект безо всякого вызова delete (delete применяется только для удаления объектов из кучи).
Чтобы убедиться в этом, модифицируем функцию main нашего предыдущего примера следующим образом:
main()
{
MyClass zzz;
zzz.demo();
}
Листинг 40
Результат компиляции в общем случае должен выглядеть так:
main proc near ; CODE XREF: start+AFp
var_4 = byte ptr -4
; локальная переменная zzz – экземпляр объекта MyClass