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

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

 #include  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 comstackndo con “Microsoft (R) 32-bit C / C ++ Optimizing Compiler versión 14.00.50727.762 para 80×86” desde Visual Studio 2005. La línea de comando es cl /EHa my.cpp .

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

El destructor no se llama porque se invoca terminate () para la excepción no controlada antes de que la stack 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 Si no se encuentra un controlador coincidente en un progtwig, la función termina ()
   (_except.terminate_) se llama.  Si la stack está desenrollada o no
   antes de llamar a terminate () es definido por la implementación.

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 stack”. Su código original no contiene try block, por eso no se desenrolla la stack .

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

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

También asumí que el comstackdor 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?

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))

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 stack, 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)