c++ - ¿Es seguro "borrar esto"?
runtime-error self-destruction (10)
Esta pregunta ya tiene una respuesta aquí:
- ¿Eliminar esto está permitido? 10 respuestas
En mis pruebas básicas iniciales, es perfectamente seguro hacerlo. Sin embargo, me ha sorprendido que intentar manipular this
más tarde en una función que delete
s podría ser un error de tiempo de ejecución. ¿Es esto cierto, y normalmente es seguro delete this
? ¿o solo hay ciertos casos en los que es seguro?
¡pero no lo hagas en el destructor!
Eliminar esto es perfectamente legal ya que otros ya han mencionado. Es arriesgado por una razón adicional que no ha sido mencionada aún: usted está asumiendo que el objeto ha sido asignado en el montón. Esto puede ser difícil de garantizar, aunque en el caso de las implementaciones de recuento de referencia no suele ser un problema.
Es seguro eliminar "esto" siempre que sea esencialmente la última operación en el método. De hecho, varias API de nivel profesional lo hacen (ver la implementación CComObject de ATL para ver un ejemplo).
El único peligro es intentar acceder a cualquier otro dato de miembro después de llamar a "eliminar esto". Esto es ciertamente inseguro.
Legal Sí
Seguro No
Sí. Debería estar perfectamente bien. "Esto" es solo un puntero. Cualquier puntero hará para eliminar. La información sobre cómo eliminar un objeto está contenida en los registros del montón. Así es como IUnknown :: Release () generalmente se implementa en objetos COM.
Según lo expresado por otros, elimine este es un idioma válido, pero para que sea seguro, debe asegurarse de que el objeto nunca se ejemplifique en la pila.
Una forma de hacerlo es hacer que tanto el constructor como el destructor sean privados e imponer la creación de objetos mediante una función de fábrica de clases que crea el objeto en el montón y le devuelve un puntero. La fábrica de clases puede ser una función miembro estática o una función amiga. La limpieza se puede hacer a través de un método Delete () en el objeto que hace "eliminar esto". Los objetos COM funcionan básicamente de esta manera, excepto que además son referencias contadas con el "eliminar esto" que ocurre cuando el recuento de referencias se reduce a cero.
Si está heredando de una clase base y le dio eliminar esto en la función de clase base, usar un puntero de clase derivado causará un bloqueo. P.ej:
class Base
{
virtual void Release()
{
delete this;
}
}
class Derived : public Base
{
void Foo()
{
...
}
}
main()
{
Base *ptrDerived = new Derived();
ptrDerived->release();
ptrDerived->Foo() //Crash
}
eliminar esto puede causar un problema cuando tiene subclases del objeto que está eliminando. Recuerde que la construcción comienza de arriba hacia abajo y la eliminación comienza de abajo hacia arriba. Entonces, si eliminar esto está en el medio de la jerarquía, básicamente pierdes todos los objetos debajo de esta clase en particular.
eliminar esto es muy útil cuando está implementando un objeto de referencia contado, un ejemplo de lo cual son las clases COM.
Read para una discusión similar. Su comprensión es correcta, ya que funciona, es necesaria y puede ser peligrosa ya que no puede acceder a ella después.
delete this
es legal y hace lo que cabría esperar: llama al destructor de su clase y libera la memoria subyacente. Después de delete this
, su valor de this
puntero no cambia, por lo que ahora es un puntero colgante que no debe desreferenciarse. Eso incluye desreferenciación implícita utilizando las variables de miembro de la clase.
Normalmente se encuentra en las clases contadas por referencia que, cuando el recuento de ref se reduce a 0, la función de miembro DecrementRefCount()
/ Release()
/ whatever llama a delete this
.
delete this
generalmente se considera una forma muy mala por muchas razones. Es fácil acceder accidentalmente a las variables miembro después de delete this
. Es posible que el código de llamada no se dé cuenta de que su objeto se ha autodestruido.
Además, delete this
es un "olor a código" que su código podría no tener una estrategia simétrica para la propiedad del objeto (quién asigna y quién elimina). Un objeto no podría haberse asignado a sí mismo con new
, por lo que llamar delete this
significa que la clase A está asignando un objeto, pero la clase B más tarde lo está liberando [self].