que programacion orientada objetos objeto herencia ejemplo destructores crear constructores como c++ destructor lifetime

herencia - programacion orientada a objetos c++



¿Revive el objeto del destructor en C++? (6)

Aquí hay una idea:

C* gPhoenix= nullptr; C::~C () { gPhoenix= new C (*this); // note: loses any further-derived class ("slice") }

Ahora, si los objetos involucrados (bases o miembros) realmente tienen destructores que hacen algo, esto se encuentra con un problema si delete gPhoenix; así que necesitarás mecanismos más elaborados dependiendo de lo que realmente está tratando de lograr. Pero no tiene ningún objetivo real, solo una exploración curiosa, por lo que señalarlo debería ser suficiente.

Cuando se llama al cuerpo del destructor, el objeto sigue siendo perfectamente bueno. Aparece perfectamente vital y normal a medida que realiza llamadas normales a la función miembro desde el destructor.

La memoria que posee el objeto será reclamada, por lo que no puede quedarse en el lugar. Y después de dejar el cuerpo, otra destrucción tiene lugar automáticamente y no puede ser interferida. Pero, puedes duplicar el objeto antes de que eso suceda.

Descargo de responsabilidad: Sé que este es un mal diseño, simplemente hago la pregunta por curiosidad para tratar de obtener un conocimiento más profundo de cómo funciona el destructor en C ++.

En C #, se puede escribir: GC.KeepAlive(this) en el destructor de una clase (ver edición más abajo) , y eso significaría que el objeto seguirá vivo en la memoria incluso después de que se complete la llamada del destructor.

¿El diseño de C ++ permite revivir un objeto del destructor similar al algoritmo de C # descrito anteriormente?

Edición : Como se indica en una respuesta a continuación, GC.ReRegisterForFinalize() está más estrechamente relacionado con la pregunta que GC.KeepAlive(this) .


Como ya se ha señalado , GC.KeepAlive no hace eso.

Mientras .NET GC.ReRegisterForFinalize , es posible resucitar del finalizador usando GC.ReRegisterForFinalize , aún puede obtener una referencia a él si tiene una WeakReference o GCHandle tracking GCHandle , o simplemente puede dar this a algo fuera de la clase. Hacer eso abortará la destrucción.

Ese es un viejo truco para detectar la recolección de basura en .NET 2.0 que ya no es relevante , pero aún funciona (un poco, la recolección de basura ahora puede ser parcial, y se realiza en paralelo con otros subprocesos).

Se debe hacer hincapié en el hecho de que en .NET está utilizando un finalizador , que se ejecuta antes de la destrucción, y puede evitarlo. Entonces, si bien es técnicamente correcto que no puede recuperar un objeto después de la destrucción, en cualquier idioma , puede acercarse al comportamiento que describe en .NET, excepto que use GC.ReRegisterForFinalize en GC.ReRegisterForFinalize lugar.

En C ++, ya se le ha dado la respuesta correcta .


En caso de que ayude, la función del destructor y la asignación de memoria son distintas.

El destructor es solo una función. Puedes llamarlo explícitamente. Si no hace nada destructivo, volver a llamarlo (por ejemplo, cuando el objeto se sale del alcance o se elimina) no es necesariamente problemático, aunque sería muy extraño; posiblemente hay una sección que trata esto en la norma. Vea el ejemplo a continuación. Por ejemplo, algunos contenedores STL llaman explícitamente al destructor, ya que administran los tiempos de vida de los objetos y la asignación de memoria por separado.

Por lo general, el compilador insertará un código para llamar al destructor cuando una variable automática se salga de su alcance o cuando un objeto asignado a un montón se destruya con la eliminación. Esta desasignación de memoria no se puede alterar dentro del destructor.

Puede hacerse cargo de la asignación de memoria proporcionando implementaciones adicionales del nuevo operador, o utilizando las existentes como la nueva ubicación, pero el comportamiento predeterminado general es que el compilador llamará a su destructor, y esa es una oportunidad para poner en orden. El hecho de que alguna memoria se borrará posteriormente está fuera del control del destructor.

#include <iostream> #include <iomanip> namespace test { class GotNormalDestructor { public: ~GotNormalDestructor() { std::wcout << L"~GotNormalDestructor(). this=0x" << std::hex << this << L"/n"; } }; class GotVirtualDestructor { public: virtual ~GotVirtualDestructor() { std::wcout << L"~GotVirtualDestructor(). this=0x" << std::hex << this << L"/n"; } }; template <typename T> static void create_destruct_delete(wchar_t const name[]) { std::wcout << L"create_destruct_delete<" << name << L">()/n"; { T t; std::wcout << L"Destructing auto " << name << L" explicitly./n"; t.~T(); std::wcout << L"Finished destructing " << name << L" explicitly./n"; std::wcout << name << L" going out of scope./n"; } std::wcout << L"Finished " << name << L" going out of scope./n"; std::wcout << L"/n"; } template <typename T> static void new_destruct_delete(wchar_t const name[]) { std::wcout << L"new_destruct_delete<" << name << L">()/n"; T *t = new T; std::wcout << L"Destructing new " << name << L" explicitly./n"; t->~T(); std::wcout << L"Finished destructing new " << name << L" explicitly./n"; std::wcout << L"Deleting " << name << L"./n"; delete t; std::wcout << L"Finished deleting " << name << L"./n"; std::wcout << L"/n"; } static void test_destructor() { { std::wcout << L"/n===auto normal destructor variable===/n"; GotNormalDestructor got_normal; } { std::wcout << L"/n===auto virtual destructor variable===/n"; GotVirtualDestructor got_virtual; } { std::wcout << L"/n===new variables===/n"; new_destruct_delete<GotNormalDestructor>(L"GotNormalDestructor"); new_destruct_delete<GotVirtualDestructor>(L"GotVirtualDestructor"); } { std::wcout << L"/n===auto variables===/n"; create_destruct_delete<GotNormalDestructor>(L"GotNormalDestructor"); create_destruct_delete<GotVirtualDestructor>(L"GotVirtualDestructor"); } std::wcout << std::endl; } } int main(int argc, char *argv[]) { test::test_destructor(); return 0; }

Salida de muestra

===auto normal destructor variable=== ~GotNormalDestructor(). this=0x0x23fe1f ===auto virtual destructor variable=== ~GotVirtualDestructor(). this=0x0x23fe10 ===new variables=== new_destruct_delete<GotNormalDestructor>() Destructing new GotNormalDestructor explicitly. ~GotNormalDestructor(). this=0x0x526700 Finished destructing new GotNormalDestructor explicitly. Deleting GotNormalDestructor. ~GotNormalDestructor(). this=0x0x526700 Finished deleting GotNormalDestructor. new_destruct_delete<GotVirtualDestructor>() Destructing new GotVirtualDestructor explicitly. ~GotVirtualDestructor(). this=0x0x526700 Finished destructing new GotVirtualDestructor explicitly. Deleting GotVirtualDestructor. ~GotVirtualDestructor(). this=0x0x526700 Finished deleting GotVirtualDestructor. ===auto variables=== create_destruct_delete<GotNormalDestructor>() Destructing auto GotNormalDestructor explicitly. ~GotNormalDestructor(). this=0x0x23fdcf Finished destructing GotNormalDestructor explicitly. GotNormalDestructor going out of scope. ~GotNormalDestructor(). this=0x0x23fdcf Finished GotNormalDestructor going out of scope. create_destruct_delete<GotVirtualDestructor>() Destructing auto GotVirtualDestructor explicitly. ~GotVirtualDestructor(). this=0x0x23fdc0 Finished destructing GotVirtualDestructor explicitly. GotVirtualDestructor going out of scope. ~GotVirtualDestructor(). this=0x0x23fdc0 Finished GotVirtualDestructor going out of scope.


En realidad, tergiversas lo que hace GC.KeepAlive en .NET. No se debe utilizar en un destructor de un objeto para evitar que se destruya ese objeto; en realidad, GC.KeepAlive() está vacío y no tiene implementación. Vea el código fuente de .NET here .

Se asegura de que el objeto pasado como parámetro no se recoja antes de que se GC.KeepAlive la llamada a GC.KeepAlive . El objeto pasado a KeepAlive como un parámetro puede ser recolectado inmediatamente después de la llamada a GC.KeepAlive . Dado que KeepAlive no tiene una implementación real, esto sucede únicamente por el hecho de que el compilador debe mantener una referencia al objeto que se debe pasar como parámetro a KeepAlive . En su lugar, también se podría usar cualquier otra función (que no esté integrada por el compilador o el tiempo de ejecución) que tome el objeto como parámetro.


Eso no es posible en ningún idioma.

Tu entendimiento está un poco apagado. GC.KeepAlive marcará el objeto como no recolectable por el recolector de basura. Esto evitará que la estrategia de recolección de basura destruya el objeto y es útil si el objeto se usa en un código no administrado donde el recolector de basura no puede hacer un seguimiento del uso. Esto no significa que el objeto esté en la memoria después de la destrucción.

Una vez que un objeto comienza la destrucción, el código liberará recursos (memoria, manejadores de archivos, conexiones de red). El orden suele ser desde la clase derivada más profunda hasta la clase base. Si algo en el medio evitara la destrucción, no hay garantía de que estos recursos puedan volver a adquirirse y que el objeto se encuentre en un estado inconsistente.

Lo que más desea es tener un std::shared_ptr que std::shared_ptr un seguimiento de las copias y referencias y solo destruya el objeto una vez que nadie lo necesite más.


La respuesta corta es no. C ++ no emplea recolección de basura, como Java o C #. Cuando un objeto es destruido, es destruido inmediatamente. Ido para siempre Se unió al coro invisible. Suspirando por los fiordos, etc ...

Y decir esto un par de veces con diferentes palabras para que no haya una posible reinterpretación fácil ...

El destructor se invoca como parte de la destrucción de objetos. La destrucción de objetos consiste en invocar el destructor y desasignar la memoria que se utilizó para el objeto en sí. Es un proceso único, no dos procesos separados. Mientras se ejecuta el destructor, el objeto todavía existe, para que lo use el destructor, pero existe en el tiempo prestado. Es una conclusión inevitable que el objeto será vaporizado tan pronto como el destructor regrese. Una vez que se invoca un destructor, el objeto será destruido y nada cambiará su destino.

Comprenda esto: la razón por la que se invoca un destructor es porque: el objeto se asignó originalmente en el montón con "nuevo", y ahora se está "eliminando" d. "eliminar" significa "eliminar", no "eliminar tal vez". Así que el objeto está siendo eliminado. O, si el objeto fue asignado en la pila, el hilo de ejecución salió del alcance, por lo que todos los objetos declarados en el alcance se destruyen. El destructor, técnicamente, es invocado como resultado de la destrucción del objeto. Entonces, el objeto está siendo destruido. El fin.

Dicho esto, C ++ le permite implementar un asignador personalizado para sus clases. Si lo desea, puede escribir sus propias funciones de asignación de memoria personalizada y de desasignación que implementan cualquier funcionalidad que desee. Aunque estos nunca se usan para apilar objetos asignados (es decir, variables locales).