En programación orientada a objetos , un destructor (a veces abreviado dtor [1] ) es un método que se invoca mecánicamente justo antes de que se libere la memoria del objeto . [2] Puede ocurrir cuando su vida útil está vinculada al ámbito y la ejecución sale del ámbito, cuando está incrustado en otro objeto cuya vida útil termina, o cuando se asignó dinámicamente y se libera explícitamente. Su propósito principal es liberar los recursos (asignaciones de memoria, archivos abiertos o sockets, conexiones de base de datos , bloqueos de recursos , etc.) que fueron adquiridos por el objeto durante su vida y/o anular el registro de otras entidades que puedan mantener referencias a él. El uso de destructores es necesario para el proceso de adquisición de recursos es inicialización (RAII).
En la mayoría de los tipos de algoritmos de recolección automática de basura , la liberación de memoria puede ocurrir mucho tiempo después de que el objeto se vuelve inalcanzable, lo que hace que los destructores (llamados finalizadores en este caso) no sean adecuados para la mayoría de los propósitos. En dichos lenguajes, la liberación de recursos se realiza a través de una construcción léxica (como try..finally, "with" de Python o "try-with-resources" de Java), que es el equivalente a RAII, o explícitamente al llamar a una función (equivalente a la eliminación explícita); en particular, muchos lenguajes orientados a objetos utilizan el patrón Dispose .
~this()
(mientras que los constructores se declaran con this()
).destructor
y pueden tener nombres definidos por el usuario, pero en su mayoría son nombrados Destroy
.dealloc
.DESTROY
; en la extensión del sistema de objetos Moose , se llama DEMOLISH
.__destruct
. No había destructores en versiones anteriores de PHP. [3]__del__
métodos llamados destructores en la guía del lenguaje Python 2, [4] pero en realidad son finalizadores como se reconoce en Python 3. [5]drop
. [6]deinit
.El destructor tiene el mismo nombre que la clase, pero con una tilde (~) antes de él. [2] Por ejemplo, una clase llamada foo tendrá el destructor . Además, los destructores no tienen parámetros ni tipos de retorno. [2] Como se indicó anteriormente, un destructor para un objeto se llama siempre que finaliza la vida útil del objeto. [2] Si el objeto se creó como una variable automática , su vida útil finaliza y el destructor se llama automáticamente cuando el objeto sale del ámbito. Debido a que C++ no tiene recolección de basura, si el objeto se creó con una declaración (dinámicamente en el montón ), entonces se llama a su destructor cuando se aplica el operador a un puntero al objeto. Por lo general, esa operación ocurre dentro de otro destructor, típicamente el destructor de un objeto puntero inteligente .~foo()
new
delete
En las jerarquías de herencia, la declaración de un destructor virtual en la clase base garantiza que los destructores de las clases derivadas se invoquen correctamente cuando se elimine un objeto mediante un puntero a la clase base. Los objetos que se puedan eliminar de esta manera deben heredar un destructor virtual.
Un destructor nunca debería lanzar una excepción. [7]
Los tipos escalares que no son de clase tienen lo que se llama unapseudodestructor al que se puede acceder mediantetypedef
argumentos de plantilla o de tipo. Esta construcción permite escribir código sin tener que saber si existe un destructor para un tipo determinado.
int f () { int a = 123 ; usando T = int ; a . ~ T (); devuelve a ; // comportamiento indefinido }
En versiones anteriores del estándar, se especificaba que los pseudodestructores no tenían efecto; sin embargo, eso se cambió en un informe de defectos para que finalizaran la vida útil del objeto en el que se invocaban. [8]
#include <cstring> #include <iostream> clase Foo { público : Foo () : datos_ ( nuevo char [ tamaño de ( "¡Hola, mundo!" )]) { std :: strcpy ( datos_ , "¡Hola, mundo!" ); } Foo ( const Foo & other ) = delete ; // deshabilitar la construcción de copia Foo & operator = ( const Foo & other ) = delete ; // deshabilitar la asignación ~ Foo ( void ) { eliminar [] datos_ ; } privado : amigo std :: ostream & operator << ( std :: ostream & os , const Foo & foo ) { os << foo.data_ ; return os ; } char * datos_ ; }; int main () { Foo foo ; std :: cout << foo << std :: endl ; }
Los objetos que no se pueden copiar y/o asignar de forma segura deben ser deshabilitados de dicha semántica declarando sus funciones correspondientes como eliminadas dentro de un nivel de encapsulamiento público. Se puede encontrar una descripción detallada de este método en el popular libro de Scott Meyers , Effective Modern C++ (Ítem 11: "Preferir funciones eliminadas a funciones privadas indefinidas". [9] ).
El compilador C de GNU Compiler Collection viene con dos extensiones que permiten implementar destructores:
destructor
atributo function [10] permite definir funciones destructoras priorizadas a nivel global: cuando main()
retorna, estas funciones son llamadas en orden de prioridad antes de que el proceso termine. Véase también: Hacking the art of exploitation . [11]Los destructores en Xojo (REALbasic) pueden adoptar una de dos formas. Cada forma utiliza una declaración de método regular con un nombre especial (sin parámetros ni valor de retorno). La forma más antigua utiliza el mismo nombre que la clase con un prefijo ~ (tilde). La forma más nueva utiliza el nombre Destructor
. La forma más nueva es la preferida porque facilita la refactorización de la clase.
Clase Foobar // Forma antigua Subtítulo ~Foobar() Fin del subtítulo // Nueva forma Subdestructor() Fin del subtítuloFin de clase