c++ exception visual-c++ destructor stack-unwinding

c++ - ¿Por qué no se llama a destructor a la excepción?



exception visual-c++ (6)

El destructor no se llama porque se invoca terminate () para la excepción no controlada antes de que la pila se desenrolle.

Los detalles específicos de lo que dice la especificación C ++ están fuera de mi conocimiento, pero un seguimiento de depuración con gdb y g ++ parece confirmar esto.

De acuerdo con el borrador de la sección estándar 15.3 viñeta 9:

9 If no matching handler is found in a program, the function terminate() (_except.terminate_) is called. Whether or not the stack is unwound before calling terminate() is implementation-defined.

Esperaba que A::~A() se llamara en este programa, pero no es así:

#include <iostream> struct A { ~A() { std::cout << "~A()" << std::endl; } }; void f() { A a; throw "spam"; } int main() { f(); }

Sin embargo, si cambio la última línea a

int main() try { f(); } catch (...) { throw; }

entonces se llama A::~A() .

Estoy compilando con "Microsoft (R) 32-bit C / C ++ Optimizing Compiler versión 14.00.50727.762 para 80x86" desde Visual Studio 2005. La línea de comando es cl /EHa my.cpp .

¿El compilador está correcto como de costumbre? ¿Qué dice la norma sobre este asunto?


En el segundo ejemplo, se llama al dtor cuando sale del bloque try {}.

En el primer ejemplo, se llama al dtor cuando el programa se apaga después de salir de la función main () --- para ese momento cout ya puede haber sido destruido.


Esta pregunta es fácil de buscar en Google, así que comparto mi situación aquí.

Asegúrese de que su excepción no cruce el límite extern "C" o use la opción / EH de MSVC (Habilite las excepciones C ++ = Sí con las funciones Extern C (/ EH))


Estados de especificación de lenguaje C ++: El proceso de invocación de destructores para objetos automáticos construidos en la ruta desde un bloque try a una expresión throw se denomina "desenrollado de pila". Su código original no contiene try block, por eso no se desenrolla la pila .


Lo siento, no tengo una copia del estándar sobre mí.
Definitivamente me gustaría obtener una respuesta definitiva a esto, por lo que alguien con copia del estándar desea compartir el capítulo y el versículo sobre lo que está sucediendo:

Desde mi entendimiento, terminar solo se llama iff:

  • El mecanismo de manejo de excepciones no puede encontrar un controlador para una excepción lanzada.
    Los siguientes son casos más específicos de esto:
    • Durante el desenrollado de la pila, una excepción se escapa de un destructor.
    • Una expresión lanzada, una excepción se escapa del constructor.
    • Una excepción se escapa del constructor / destructor de una estática no local (es decir, global)
    • Una excepción escapa de una función registrada con atexit ().
    • Una excepción escapa de main ()
  • Intentando volver a lanzar una excepción cuando actualmente no se está propagando ninguna excepción.
  • Una excepción inesperada se escapa de una función con especificadores de excepciones (a través de inesperado)

También asumí que el compilador no genera el código relativo a "a" ya que no está referenciado, pero aún así, no es el comportamiento correcto ya que el destructor hace algo que debe ser ejecutado.

Entonces, probé en VS2008 / vc9 (+ SP1), Depurar y Liberar y ~ A se llama después de que se lanza la excepción, saliendo de f () - ese es el comportamiento correcto, si estoy en lo cierto.

Ahora probé con VS2005 / vc8 (+ SP1) y es el mismo comportamiento.

Usé puntos de interrupción para estar seguro. Acabo de consultar con la consola y también tengo el mensaje "~ A". Tal vez lo hiciste mal en otro lugar?