2011-08-22 19 views
13

¿Cuál es una buena manera en C++ para detectar en un destructor que se está ejecutando durante el desenrollado de la pila debido a una excepción lanzada en oposición a una salida normal del alcance que desencadena el destructor? Me gustaría saber para poder crear una clase que tenga algún código de limpieza que siempre se ejecute en la salida normal pero se omita cuando ocurra una excepción.¿Detecta cuándo se ejecuta el destructor debido a una excepción?

+0

¡Pregunta interesante! Estoy tentado de decir que no se puede hacer, porque los objetos realmente no saben que una excepción está activa, simplemente salen del alcance ya que la excepción desenrolla la pila, como si salieran de cualquier otra alcance. En todo caso, necesitaría algún "hackeo" específico de la plataforma ... –

+1

¿Por qué quiere evitar la limpieza durante el desenrollado de la pila? –

+0

@Eric Z: Pensé en usar esto para el registro automático de 'stack'. Algo similar a 'Log xxx (" funcA - ", arg1, arg2, arg3);', pero instrumentar las funciones es tedioso. –

Respuesta

16

std::uncaught_exception() (definido en <exception>) le informará por su destructor si se llamó debido a una excepción:

class A 
{ 
public: 
    ~A() 
    { 
     if (std::uncaught_exception()) { 
      // Called because of an exception 
     } else { 
      // No exception 
     } 
    } 
}; 
+0

¡Agradable, nunca supe que esto existía! :-) –

+0

No es tan agradable como podría pensar - vea el artículo vinculado en mi publicación. – Simon

0

Esta es una manera que puedo pensar, pero parece torpe:

{ 
    myCleanupClass unwindAction; 
    try { 
    // do some work which may throw exception. 
    } catch (...) { 
    unwindAction.disableDestructorWork(); 
    throw; 
    } 
} 
1

No haga eso a menos que tenga una buena razón. El desenrollado de la pila es una función de lenguaje tal que todos los objetos automáticos dentro del bloque try se aplicarán para desasignar, de modo que los recursos dentro de ellos tengan la oportunidad de liberarse.

Desea omitir la limpieza en dtor durante el desenrollado de la pila, lo que evita la intención original de la misma. Y correrá el riesgo de perder recursos.

Ejemplo

class CDBConnection 
{ 
    public: 
    CDBConnection() 
    { 
     m_db.open(); 
    } 
    ~CDBConnection() 
    { 
     if (!std::uncaught_exception()) 
     m_db.close(); 

     // if this is called during a stack unwinding, 
     // your DB connection will not be closed for sure. 
     // That's a resource leakage. 
    } 
    //.. 
    private: 
    DB m_db; 
}; 

void main() 
{ 
    //.. 
    try 
    { 
    // code that may throw 
    CDBConnection db; 
    //..   
    } 
    catch(const CDBException& exp) 
    { 
    // properly handle the exception 
    } 
} 
4

Probablemente this artículo le ayudará. El artículo le mostrará los problemas con std :: uncaught_exception() y contiene un consejo sobre cómo lidiar con excepciones en destructores.

Cuestiones relacionadas