Traté de llamar ::deletepara una clase en el operator deletemismo. Pero el destructor no se llama.
Definí una clase MyClassque operator deleteha sido sobrecargada. Lo global operator deletetambién está sobrecargado. El sobrecargado operator deletede MyClassllamará al global sobrecargado 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;
}
El resultado es:
Newing MyClass...
Global newing...
Constructing MyClass...
End of newing MyClass...
Constructing MyClass...
Destroying MyClass...
Deleting MyClass...
Global deleting...
End of deleting MyClass...
Real:
Solo hay una llamada al destructor antes de llamar al sobrecargado operator deletede MyClass.
Esperado:
Hay dos llamadas al destructor. Uno antes de llamar al sobrecargado operator deletede MyClass. Otro antes de llamar a lo global operator delete.
c++
delete-operator
expinc
fuente
fuente

MyClass::operator new()debe asignar memoria en bruto, de (al menos)sizebytes. No debe intentar construir completamente una instancia deMyClass. El constructor deMyClassse ejecuta despuésMyClass::operator new(). Luego, ladeleteexpresión inmain()llama al destructor y libera la memoria (sin volver a llamar al destructor). La::delete pexpresión no tiene información sobre el tipo deppuntos de objeto , ya quepes avoid *, por lo que no puede invocar al destructor.::delete p;provoca un comportamiento indefinido ya que el tipo de*pno es el mismo que el tipo del objeto que se está eliminando (ni una clase base con destructor virtual)void*operando está explícitamente mal formado. [expr.delete] / 1 : " El operando será de puntero a tipo de objeto o de tipo de clase. [...] Esto implica que un objeto no puede eliminarse usando un puntero de tipo void porque void no es un tipo de objeto. * "@OP He modificado mi respuesta.Respuestas:
Estás haciendo mal uso
operator newyoperator delete. Estos operadores son funciones de asignación y desasignación. No son responsables de construir o destruir objetos. Solo son responsables de proporcionar la memoria en la que se colocará el objeto.Las versiones globales de estas funciones son
::operator newy::operator delete.::newy::deleteson nuevas / eliminar-expresiones, como sonnew/delete, que difieren de esas, en eso::newy::deleteomitirán las sobrecargasoperator new/ específicas de claseoperator delete.Las nuevas expresiones / delete-build construyen / destruyen y asignan / desasignan (llamando al apropiado
operator newooperator deleteantes de la construcción o después de la destrucción).Dado que su sobrecarga solo es responsable de la parte de asignación / desasignación, debe llamar
::operator newy en::operator deletelugar de::newy::delete.El
deleteindelete myClass;es responsable de llamar al destructor.::delete p;no llama al destructor porqueptiene tipovoid*y, por lo tanto, la expresión no puede saber a qué destructor llamar. Probablemente llamará a su reemplazo::operator deletepara desasignar la memoria, aunque el uso de unvoid*operando as para una expresión de eliminación está mal formado (vea la edición a continuación).::new MyClass();llama a su reemplazado::operator newpara asignar memoria y construye un objeto en él. El puntero a este objeto se devuelve en cuantovoid*a la nueva expresión enMyClass* myClass = new MyClass();, que luego construirá otro objeto en esta memoria, terminando la vida útil del objeto anterior sin llamar a su destructor.Editar:
Gracias al comentario de @ MM sobre la pregunta, me di cuenta de que un
void*como operando::deleteestá mal formado. ( [expr.delete] / 1 ) Sin embargo, los principales compiladores parecen haber decidido advertir sobre esto, no por error. Antes de que estuviera mal formado, usando::deleteunvoid*comportamiento ya indefinido, vea esta pregunta .Por lo tanto, su programa está mal formado y no tiene ninguna garantía de que el código realmente haga lo que describí anteriormente si aún logra compilar.
Como señaló @SanderDeDycker debajo de su respuesta, también tiene un comportamiento indefinido porque al construir otro objeto en la memoria que ya contiene un
MyClassobjeto sin llamar primero al destructor de ese objeto, está violando [basic.life] / 5 que prohíbe hacerlo si el El programa depende de los efectos secundarios del destructor. En este caso, laprintfdeclaración en el destructor tiene tal efecto secundario.fuente
Sus sobrecargas específicas de clase se realizan incorrectamente. Esto se puede ver en su salida: ¡se llama al constructor dos veces!
En la clase específica
operator new, llame al operador global directamente:Del mismo modo, en la clase específica
operator delete, hacer:Consulte la
operator newpágina de referencia para más detalles.fuente
Ver referencia de CPP :
Delete (y new) solo son responsables de la parte de 'gestión de memoria'.
Por lo tanto, está claro y se espera que el destructor solo se llame una vez, para limpiar la instancia del objeto. Se llamaría dos veces, cada destructor tendría que verificar si ya se había llamado.
fuente
operator delete()función no es lo mismo que una expresión de eliminación. Se llama al destructor antes de llamar a laoperator delete()función.