new how delete c++ destructor undefined-behavior lifetime explicit-destructor-call

c++ - how - Llamada explícita a destructor



destroy object c++ (3)

¿Está el texto simplemente equivocado sobre el error de tiempo de ejecución?

Está mal.

¿O es realmente común tener un error de tiempo de ejecución? ¿O tal vez mi compilador implementó algún tipo de mecanismo de protección contra este tipo de cosas?

No puedes saberlo, y esto es lo que sucede cuando tu código invoca un comportamiento indefinido ; No sabes lo que pasará cuando lo ejecutes.

En su caso, tuvo (des) suerte * y funcionó, mientras que para mí, causó un error (doble gratis).

* Porque si recibiste un error, comenzarías a depurar, de lo contrario, en un proyecto grande, por ejemplo, podrías perderlo ...

Me topé con el siguiente fragmento de código:

#include <iostream> #include <string> using namespace std; class First { string *s; public: First() { s = new string("Text");} ~First() { delete s;} void Print(){ cout<<*s;} }; int main() { First FirstObject; FirstObject.Print(); FirstObject.~First(); }

El texto dice que este fragmento debería causar un error de tiempo de ejecución. Ahora, no estaba muy seguro de eso, así que traté de compilarlo y ejecutarlo. Funcionó. Lo extraño es que, a pesar de la simplicidad de los datos involucrados, el programa tartamudeó después de imprimir "Texto" y solo después de un segundo se completó.

Agregué una cadena para ser impresa en el destructor ya que no estaba seguro de si era legal llamar explícitamente a un destructor como ese. El programa imprimió dos veces la cadena. Entonces, supongo que se llama al destructor dos veces, ya que la terminación normal del programa desconoce la llamada explícita e intenta destruir el objeto nuevamente.

Una simple búsqueda confirmó que llamar explícitamente a un destructor en un objeto automatizado es peligroso, ya que la segunda llamada (cuando el objeto está fuera de alcance) tiene un comportamiento indefinido. Así que tuve suerte con mi compilador (VS 2017) o este programa específico.

¿Está el texto simplemente equivocado sobre el error de tiempo de ejecución? ¿O es realmente común tener un error de tiempo de ejecución? ¿O tal vez mi compilador implementó algún tipo de mecanismo de protección contra este tipo de cosas?


Una simple búsqueda confirmó que llamar explícitamente a un destructor en un objeto automatizado es peligroso, ya que la segunda llamada (cuando el objeto está fuera de alcance) tiene un comportamiento indefinido.

Eso es verdad. Undefined Behavor se invoca si destruye explícitamente un objeto con almacenamiento automático. Aprende más sobre esto .

Así que tuve suerte con mi compilador (VS 2017) o este programa específico.

Yo diría que tuviste mala suerte . Lo mejor (para usted, el codificador) que puede suceder con UB es un fallo en la primera ejecución. Si parece funcionar bien, el choque podría ocurrir el 19 de enero de 2038 en producción.

¿Está el texto simplemente equivocado sobre el error de tiempo de ejecución? ¿O es realmente común tener un error de tiempo de ejecución? ¿O tal vez mi compilador implementó algún tipo de mecanismo de protección contra este tipo de cosas?

Sí, el texto está un poco mal. El comportamiento indefinido es indefinido . Un error en tiempo de ejecución es solo una de las muchas posibilidades (incluidos los demonios nasales).

Una buena lectura sobre el comportamiento indefinido: ¿Qué es el comportamiento indefinido?


No, esto es simplemente un comportamiento indefinido del borrador del estándar de C ++ [class.dtor]p16 :

Una vez que se invoca un destructor para un objeto, el objeto ya no existe; el comportamiento no está definido si se invoca el destructor para un objeto cuya duración ha finalizado ([basic.life]). [Ejemplo: si el destructor para un objeto automático se invoca explícitamente y el bloque se deja posteriormente de una manera que normalmente invocaría la destrucción implícita del objeto, el comportamiento no está definido. - ejemplo final

y podemos ver a partir de la definición de comportamiento indefinido :

Comportamiento para el que este documento no impone requisitos.

No se puede tener expectativas en cuanto a los resultados. Puede haberse comportado de esa manera para el autor en su compilador específico con opciones específicas en una máquina específica, pero no podemos esperar que sea un resultado portátil ni confiable. Aunque hay casos en los que la implementación intenta obtener un resultado específico, es solo otra forma de comportamiento indefinido aceptable.

Además, [class.dtor]p15 ofrece más contexto en la sección normativa que cito arriba:

[Nota: las llamadas explícitas de destructores rara vez son necesarias. Un uso de tales llamadas es para objetos colocados en direcciones específicas utilizando una nueva expresión de ubicación. Este uso de la colocación y destrucción explícita de objetos puede ser necesario para hacer frente a recursos de hardware dedicados y para escribir recursos de gestión de memoria. Por ejemplo,

void* operator new(std::size_t, void* p) { return p; } struct X { X(int); ~X(); }; void f(X* p); void g() { // rare, specialized use: char* buf = new char[sizeof(X)]; X* p = new(buf) X(222); // use buf[] and initialize f(p); p->X::~X(); // cleanup }

- nota final]