2008-09-02 12 views
5

Estoy trabajando en portar una aplicación de Visual C++ a GCC (debería compilarse en MingW y Linux).Manejar portably errores excepcionales en C++

El código existente usa __try { ... } __except(1) { ... } bloques en unos pocos lugares, de modo que casi nada (salvo los errores de tipo de memoria quizás fuera de memoria) haría que el programa salga sin hacer un registro mínimo.

¿Cuáles son las opciones para hacer algo similar con GCC?

Editar: Gracias por las opciones de puntero/EH en Visual Studio, lo que necesito ahora son algunos ejemplos sobre cómo manejar las señales en Linux. He encontrado this message desde 2002.

¿Qué otras señales además de SIGFPE y SIGSEVG debo tener en cuenta? (En su mayoría se preocupa por los que podrían plantearse a partir me haciendo algo mal)

Bounty Información: Quiero que mi solicitud sea capaz de auto-log tantas condiciones de error como sea posible antes de que salga.

¿Qué señales podría obtener y en cuáles sería generalmente imposible registrar un mensaje de error después? (Memoria insuficiente, ¿qué más?)

¿Cómo puedo manejar excepciones y (lo que es más importante) señales de forma portátil que el código al menos funciona igual en Linux y MingW. #ifdef está bien.

La razón por la que no solo tengo un proceso de envoltura que registra el error es que, por motivos de rendimiento, guardo algunos datos en el disco hasta último momento, así que si algo sale mal quiero hacer todos los intentos posibles para escribir los datos salen antes de salir.

Respuesta

10

try {xxx} catch (...) {xxx} sería más portátil pero podría no captar tanto. Depende de la configuración y el entorno del compilador.

Utilizando la configuración predeterminada de VC++, los errores asíncronos (SEH) no se entregan a la infraestructura C++ EH; para atraparlos, necesitas usar manejadores SEH (__try/__ excepto) en su lugar. VC++ le permite enrutar errores SEH a través del manejo de errores de C++, lo que permite capturar (...) para atrapar errores SEH; esto incluye errores de memoria como referencias a punteros nulos. Details.

En Linux, sin embargo, muchos de los errores para los que utiliza Windows SEH se indican a través de señales. Estos nunca son atrapados por try/catch; para manejarlos necesitas un manejador de señal.

0

¿Por qué no utilizar las excepciones estándar de C++ en lugar de la extensión patentada de MSFT? C++ tiene un concepto de manejo de excepciones.

struct my_exception_type : public logic_error { 
    my_exception_type(char const* msg) : logic_error(msg) { } 
}; 

try { 
    throw my_exception_type("An error occurred"); 
} catch (my_exception_type& ex) { 
    cerr << ex.what << endl; 
} 

C++ también tiene una cláusula de “cajón de sastre” por lo que si desea iniciar sesión excepciones se puede utilizar el siguiente contenedor:

try { 
    // … 
} 
catch (...) { 
} 

Sin embargo, esto no es muy eficiente en C++ porque la creación de un general, tales envoltura significa que el código de manejo debe insertarse en cada marco de pila subsiguiente por el compilador (a diferencia de los sistemas administrados como .NET donde el manejo de excepciones no tiene costo adicional mientras no se produzca ninguna excepción).

+0

El OP está buscando algo para abordar las condiciones excepcionales de menor nivel que las excepciones de nivel de lenguaje C++. En un mundo POSIX, esto significa instalar manejadores de señal para (la mayoría) de todo. En MSVC, el mecanismo __try/__ catch maneja fallas similares (incluido el equivalente de Win32 de SEGFAULT) –

+0

Derecha sobre las trampas. Pero puede configurar MSVC para atrapar SEH usando el estándar 'try' /' catch', como lo describe DrPizza. –

0

Para la portabilidad, una cosa para intentar es usar bloques try-catch para la mayoría de las excepciones vainilla y luego configurar un manejador de terminación (set_terminate_handler) para tener un gancho mínimo disponible para condiciones de salida catastróficas. También puede intentar agregar algo como un controlador atexit o on_exit. Su entorno de ejecución puede ser extraño o corrupto cuando ingresa a estas funciones, por supuesto, así que tenga cuidado de lo mucho que presume un entorno sano.

Por último, cuando se utilizan pares try-catch regulares se puede considerar el uso de la función de tratar los bloques en oposición a la apertura de un bloque try en el cuerpo de una función:

int foo(int x) try { 
    // body of foo 
} catch (...) { 
    // be careful what's done here! 
} 

son una parte relativamente desconocida de C++ y en algunos casos puede ofrecer recuperación incluso en el caso de una corrupción parcial (a pequeña escala) de la pila.

Finalmente, sí, es probable que desee investigar qué señales puede manejar por sí mismo o en las que puede abortar, y si desea menos mecanismos de manejo, puede considerar llamar a la versión sin lanzamiento del nuevo operador, y compilando para no generar excepciones de punto flotante si es necesario (siempre se puede verificar isnan (.), isfinite (.), en los resultados de FP para protegerse).

En esa última nota, tenga cuidado: he notado que las funciones de clasificación de resultados de punto flotante pueden estar en diferentes encabezados bajo linux y windows ... por lo que puede que tenga que condicionalizar esas inclusiones.

Si te sientes mal, escribe todo usando setjmp y longjmp (eso es una broma ...).

-1

Una forma que es fácil de usar, portátil y que apenas utiliza recursos sería capturar clases vacías. Sé que esto puede sonar extraño al principio, pero puede ser muy útil.

Este es un ejemplo que hice para otra pregunta que se aplica a su pregunta también: link

También, usted puede tener más de 1 trampa:

try 
{ 
    /* code that may throw exceptions */ 
} 
catch (Error1 e1) 
{ 
    /* code if Error1 is thrown */ 
} 
catch (Error2 e2) 
{ 
    /* code if Error2 is thrown */ 
} 
catch (...) 
{ 
    /* any exception that was not expected will be caught here */ 
} 
0

La captura de excepciones de C++ con catch(...) ya que pone en una zona crepuscular

Tratando de atrapar errores no detectados por catch(...) te pone directamente dentro de un comportamiento indefinido. No se garantiza que ningún código C++ funcione. Su código de registro mínimo puede hacer que se active el misil.

Mi recomendación es ni siquiera intentar catch(...). Solo capture excepciones que pueda registrar de manera significativa y segura y deje que el SO maneje el resto, si corresponde.

La depuración postmortem se pone fea si tiene un error al manejar fallas de código además de la causa raíz.

Cuestiones relacionadas