¿Puedo usar std::current_exception durante el desenrollado de la pila?

3 minutos de lectura

avatar de usuario de peper0
pimienta0

¿Debería ser posible usar std::current_exception dentro de los destructores de objetos que se destruyen durante el desenrollado de la pila?

Documentación sobre cppreference dice:

Si se llama durante el manejo de excepciones (normalmente, en una cláusula catch), captura el objeto de excepción actual (…)

Pero no me queda claro si el desenredado de la pila es parte del manejo de excepciones.

En alguna respuesta mejor clasificada en stackoverflow, el autor asume que es posible.

Hice algunas pruebas en mi compilador (g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2) y parece que std::current_exception devuelve un puntero vacío en este caso.

#include <exception>
#include <stdexcept>
#include <iostream>


struct A
{
    ~A()
    {
        std::clog << "in destructor"<<std::endl;
        std::clog << "uncaught_exception: " << std::uncaught_exception() << std::endl;
        std::clog << "current_exception: " << (bool)std::current_exception() << std::endl;
    }
};

int main(int argc, char **)
{
    try
    {
        A aa;
        std::clog << "before throw"<<std::endl;
        if(argc>1)
            throw std::runtime_error("oh no");
    }
    catch(...)
    {
        std::clog << "in catch block"<<std::endl;
        std::clog << "uncaught_exception: " << std::uncaught_exception() << std::endl;
        std::clog << "current_exception: " << (bool)std::current_exception() << std::endl;
    }

    return 0;
}

La salida es:

before throw
in destructor
uncaught_exception: 1
current_exception: 0
in catch block
uncaught_exception: 0
current_exception: 1

¿Alguien sabe lo que dice la norma?

avatar de usuario de quantdev
quantdev

El estándar C++ define current_exception() en la sección § 18.8.5 [propagation] :

(énfasis mío)

exception_ptr current_exception() noexcept;

Devuelve: un objetoException_ptr que hace referencia a la excepción manejada actualmente (15.3) o una copia de la excepción manejada actualmente, o un objetoException_ptr nulo si no se maneja ninguna excepción. El objeto al que se hace referencia seguirá siendo válido al menos mientras haya un objetoException_ptr que haga referencia a él.

y § 15.3 [except.handle]notas 7 y 8 :

  1. Se considera un manipulador activo cuando se completa la inicialización del parámetro (si lo hay) de la cláusula catch. [ Note: The stack will have
    been unwound at that point
    . — end note ]

  2. La excepción con la activación más reciente controlador que todavía está activo se llama el excepción manejada actualmente.

La excepción devuelta por current_exception() se define como la “excepción manejada actualmente”, que es la excepción del controlador activo más reciente, y un controlador está activo solo cuando se completa el desenredado de la pila.


Como han demostrado sus pruebas, no hay un “controlador activo” durante desenrollado de la pila, por lo que tampoco hay una “excepción manejada actualmente”: en ese caso, current_exception() devolverá un nulo exception_ptr.

  • “no hay una “excepción activa” durante el desenrollado de la pila” a menos que una excepción esté siendo manejada por un catch in o invocada desde un destructor.

    – Saludos y hth. – alf

    2 de febrero de 2015 a las 4:11

  • @Cheersandhth.-Af True, corregí la redacción, lea ningún “controlador activo” (redacción del estándar)

    – quantdev

    2 de febrero de 2015 a las 4:15


  • Bueno, es tan difícil acertar que Some™ sospecha que esa podría ser la razón de std::uncaught_exception siendo inservible para cualquier propósito. 😉

    – Saludos y hth. – alf

    2 de febrero de 2015 a las 4:20

  • Eso parece ser correcto. Yo también estaba sorprendido; Puedo ver buenos usos para alcanzar excepciones en d’tors; particularmente el registro basado en RAII.

    – ben

    25 de mayo de 2020 a las 13:43

¿Ha sido útil esta solución?