Eu tentei chamar ::delete
uma aula operator delete
sobre isso. Mas o destruidor não é chamado.
Eu defini uma classe MyClass
que operator delete
foi sobrecarregada. O global operator delete
também está sobrecarregado. O sobrecarregado operator delete
de MyClass
chamará o global sobrecarregado operator delete
.
class MyClass
{
public:
MyClass() { printf("Constructing MyClass...\n"); }
virtual ~MyClass() { printf("Destroying MyClass...\n"); }
void* operator new(size_t size)
{
printf("Newing MyClass...\n");
void* p = ::new MyClass();
printf("End of newing MyClass...\n");
return p;
}
void operator delete(void* p)
{
printf("Deleting MyClass...\n");
::delete p; // Why is the destructor not called here?
printf("End of deleting MyClass...\n");
}
};
void* operator new(size_t size)
{
printf("Global newing...\n");
return malloc(size);
}
void operator delete(void* p)
{
printf("Global deleting...\n");
free(p);
}
int main(int argc, char** argv)
{
MyClass* myClass = new MyClass();
delete myClass;
return EXIT_SUCCESS;
}
A saída é:
Newing MyClass...
Global newing...
Constructing MyClass...
End of newing MyClass...
Constructing MyClass...
Destroying MyClass...
Deleting MyClass...
Global deleting...
End of deleting MyClass...
Real:
Há apenas uma chamada para o destruidor antes de chamar a sobrecarga operator delete
de MyClass
.
Esperado:
Existem duas chamadas para o destruidor. Um antes de chamar o sobrecarregado operator delete
de MyClass
. Outro antes de chamar o global operator delete
.
::delete p;
provoca um comportamento indefinido, pois o tipo de *p
não é o mesmo que o tipo de objeto que está sendo eliminada (nem uma classe base com destrutor virtual)
void*
o operando é explicitamente mal formado. [expr.delete] / 1 : " O operando deve ser um ponteiro para o tipo de objeto ou de classe. [...] Isso implica que um objeto não pode ser excluído usando um ponteiro do tipo void porque void não é um tipo de objeto. * "@OP Alterei minha resposta.
MyClass::operator new()
deve alocar memória bruta, de (pelo menos)size
bytes. Não deve tentar construir completamente uma instância deMyClass
. O construtor deMyClass
é executado depoisMyClass::operator new()
. Em seguida, adelete
expressãomain()
chama o destruidor e libera a memória (sem chamar o destruidor novamente). A::delete p
expressão não possui informações sobre o tipo de objetop
apontado para, uma vez quep
é avoid *
, portanto, não pode invocar o destruidor.