2008-11-09 28 views
18

¿Hay alguna manera de detectar excepciones que de lo contrario no se han controlado (incluidas las lanzadas fuera del bloque catch)?¿Está capturando todas las excepciones de C++ no controladas?

No estoy realmente preocupado por todas las cosas normales de limpieza hechas con excepciones, solo que puedo atraparlo, escribirlo para registrar/notificar al usuario y salir del programa, ya que las excepciones en estos casos son en general fatales, errores irrecuperables.

algo como:

global_catch() 
{ 
    MessageBox(NULL,L"Fatal Error", L"A fatal error has occured. Sorry for any inconvience", MB_ICONERROR); 
    exit(-1); 
} 
global_catch(Exception *except) 
{ 
    MessageBox(NULL,L"Fatal Error", except->ToString(), MB_ICONERROR); 
    exit(-1); 
} 

Respuesta

21

Esto puede ser usado para capturar, excepciones inesperadas.

Sin un bloque intento de captura, no creo que se puede capturar las excepciones, por lo que la estructura de su programa, por lo que el código de excepción thowing está bajo el control de un try/catch.

+0

La cosa es que realmente no quiero poner toda mi aplicación en un bloque grande "super-tratar" ... ya que el rendimiento es un poco crítico ... Sé theres algunos camino a algún lado porque, por ejemplo, Visual Studio puede detectar/atrapar/lo que sea, exceptiosn, y ofrece romper y depurar. –

+0

El bloque Super try funciona. Usted paga el costo de configurarlo una vez en general. Una vez no es un problema de rendimiento. – EvilTeach

+0

solo una vez? Estoy seguro de que una vez dentro de un bloque de prueba, mantuvo algún tipo de "rastro" para limpiar después de un lanzamiento, haciendo que el costo se basara en el contenido del bloque. –

4

Esto es lo que siempre hago en main()

int main() 
{ 
    try 
    { 
     // Do Work 
    } 
    catch(std::exception const& e) 
    { 
     Log(e.what()); 
     // If you are feeling mad (not in main) you could rethrow! 
    } 
    catch(...) 
    { 
     Log("UNKNOWN EXCEPTION"); 
     // If you are feeling mad (not in main) you could rethrow! 
    } 
} 
+1

Esa es una buena forma de hacerlo, pero hay que tener en cuenta que esto no detectará posibles excepciones estáticas init (creo). – kralyk

+0

@kralyk: no hay forma de detectar excepciones generadas en constructores/destructores de objetos de duración de almacenamiento estáticos. En estos casos, se llama a 'std :: terminate()'. –

+1

Sé ... Técnicamente, podría ser posible usar set_terminate() (ver mi respuesta), pero dado que el orden de inicio estático está definido por la implementación, eso tampoco es garantía ... – kralyk

9

Puede utilizar SetUnhandledExceptionFilter en Windows, lo que capturar todas las excepciones SEH no controladas.

En general, esto será suficiente para todos sus problemas ya que IIRC todas las excepciones de C++ se implementan como SEH.

8

Sin ningún bloqueo, no se detectarán excepciones. Puede tener un bloque catch (...) en su main() (y su equivalente en cada thread adicional). En este bloque catch, puede recuperar los detalles de la excepción y puede hacer algo al respecto, como iniciar sesión y salir.

Sin embargo, también hay un inconveniente en un bloque de captura general (...): el sistema determina que la excepción ha sido manejada por usted, por lo que no le da más ayuda. En Unix/Linux, esta ayuda constituiría la creación de un archivo CORE, que podría cargar en el depurador y ver la ubicación original de la excepción no aceptada. Si lo está manejando con catch (...) esta información ya estaría perdida.

En Windows, no hay archivos CORE, por lo que sugeriría tener el bloque catch (...). A partir de ese bloque, lo más habitual es llamar a una función de resucitar la excepción real:

std::string ResurrectException() 
    try { 
     throw; 
    } catch (const std::exception& e) { 
     return e.what(); 
    } catch (your_custom_exception_type& e) { 
     return e.ToString(); 
    } catch(...) { 
     return "Ünknown exception!"; 
    } 
} 


int main() { 
    try { 
     // your code here 
    } catch(...) { 
     std::string message = ResurrectException(); 
     std::cerr << "Fatal exception: " << message << "\n"; 
    } 
} 
+2

Windows tiene archivos .dmp, que son aproximadamente equivalentes a los archivos principales, pero se cargan en el sitio web de informes de errores de Windows (si el usuario hace clic en "enviar") en lugar de ensuciar el disco duro del usuario. Además, si tiene configurado un depurador just-in-time, Windows irrumpirá en el depurador. – bk1e

+1

el constructor de std :: string podría arrojarse una excepción. Y también lo hace la impresión a std: cerr. Entonces, de nuevo, puedes tener suerte el 99% del tiempo. – rxantos

7

actualización: Esto cubre C++ 98 solamente.

A partir de More Effective C++ por Meyers (pg 76), podría definir una función a la que se llama cuando una función genera una excepción que no está definida por su especificación de excepción.

void convertUnexpected() 
{ 
    // You could redefine the exception here into a known exception 
    // throw UnexpectedException(); 

    // ... or I suppose you could log an error and exit. 
} 

En su solicitud de registro de la función:

std::set_unexpected(convertUnexpected); 

Su función convertUnexpected() se llamará si una función genera una excepción que no se define por su especificación de excepción ... que significa esto sólo funciona si está utilizando especificaciones de excepción. ; (

+3

Sé que esta respuesta se realizó mucho antes de que el estándar C++ 11 estuviera disponible, pero actualmente 'std :: set_unexpected' está en desuso. – scrutari

1

Use catch (...) en todas sus barreras de excepción (no solo en el hilo principal). Sugiero que siempre vuelva a lanzar (...) y redirija la salida/error estándar al archivo de registro, como no puedes hacer RTTI significativo en (...).Otoh, compilador GCC, como es la salida de una descripción bastante detallada sobre la excepción no controlada: el tipo, el valor de lo que(), etc.

19
+0

¿Puede acceder a la excepción en 'terminate_handler'? –

+0

@ KonstantinA.Magg No lo creo. Como la excepción puede ser de cualquier tipo, realmente no hay forma de acceder a ella ... – kralyk

+1

Sí se puede usar std :: uncaugth_exception() & std :: current_exception {) –

3

A condición de que C++ 11 está disponible, este enfoque puede ser utilizado (véase el ejemplo de: http://en.cppreference.com/w/cpp/error/rethrow_exception):

#include <iostream> 
#include <exception> 

void onterminate() { 
    try { 
    auto unknown = std::current_exception(); 
    if (unknown) { 
     std::rethrow_exception(unknown); 
    } else { 
     std::cerr << "normal termination" << std::endl; 
    } 
    } catch (const std::exception& e) { // for proper `std::` exceptions 
    std::cerr << "unexpected exception: " << e.what() << std::endl; 
    } catch (...) { // last resort for things like `throw 1;` 
    std::cerr << "unknown exception" << std::endl; 
    } 
} 

int main() { 
    std::set_terminate(onterminate); // set custom terminate handler 
    // code which may throw... 
    return 0; 
} 

este enfoque también permite personalizar la salida de la consola para las excepciones no controladas: tener algo como esto

unexpected exception: wrong input parameters 
Aborted 

en lugar de esto:

terminate called after throwing an instance of 'std::logic_error' 
    what(): wrong input parameters 
Aborted 
Cuestiones relacionadas