usar try excepciones ejemplos con como catch c++ exception callstack try-catch

try - excepciones en c++>



Call-stack para excepciones en C++ (9)

Hoy, en mi código multiplataforma de C ++, tengo un intento de captura alrededor de cada función. En cada bloque de captura agrego el nombre de la función actual a la excepción y la lanzo nuevamente, de modo que en el bloque de captura superior (donde finalmente imprimo los detalles de la excepción) tengo la pila de llamadas completa, lo que me ayuda a rastrear la causa de la excepción.

¿Es una buena práctica o hay mejores maneras de obtener la pila de llamadas para la excepción?



La respuesta a todos sus problemas es un buen depurador, generalmente http://www.gnu.org/software/gdb/ en Linux o Visual Studio en Windows. Pueden proporcionarle trazas de pila a pedido en cualquier punto del programa.

Su método actual es un verdadero dolor de cabeza de rendimiento y mantenimiento. Los depuradores se inventan para lograr su objetivo, pero sin los gastos generales.


La vinculación con la biblioteca libcsdbg (consulte https://.com/a/18959030/364818 para obtener la respuesta original) parece ser la forma más limpia de obtener un seguimiento de pila sin modificar su código fuente o el código fuente de terceros (es decir, STL).

Esto utiliza el compilador para instrumentar la colección de pila real, que es realmente lo que quieres hacer.

No lo he usado y está contaminado con GPL, pero parece la idea correcta.


Lo que estás haciendo no es una buena práctica. Este es el por qué:

1. Es innecesario.
Si compila su proyecto en modo de depuración para que se genere la información de depuración, puede obtener fácilmente los trámites para el manejo de excepciones en un depurador como GDB.

2. Es engorroso.
Esto es algo que debe recordar agregar a todas y cada una de las funciones. Si pierde una función, eso podría causar una gran confusión, especialmente si esa fue la función que causó la excepción. Y cualquiera que mire su código debería darse cuenta de lo que está haciendo. Además, apuesto a que usaste algo como __FUNC__ o __FUNCTION__ o __PRETTY_FUNCTION__, que lamentablemente no son estándar (no hay una forma estándar en C ++ para obtener el nombre de la función).

3. Es lento.
La propagación de excepciones en C ++ ya es bastante lenta, y agregar esta lógica solo hará que el codepath sea más lento. Esto no es un problema si está utilizando macros para capturar y volver a lanzar, donde puede fácilmente olvidarlo y volver a lanzar en las versiones de lanzamiento de su código. De lo contrario, el rendimiento podría ser un problema.

Buena práctica
Si bien puede que no sea una buena práctica capturar y volver a generar en todas y cada una de las funciones para crear un seguimiento de pila, es una buena práctica adjuntar el nombre del archivo, el número de línea y el nombre de la función en la que se lanzó originalmente la excepción. Si usa boost :: exception con BOOST_THROW_EXCEPTION, obtendrá este comportamiento de forma gratuita. También es bueno adjuntar información explicativa a su excepción que ayudará a depurar y manejar la excepción. Dicho esto, todo esto debería ocurrir en el momento en que se construye la excepción; una vez construido, se debe permitir que se propague a su controlador ... no debe capturar y volver a lanzar repetidamente más de lo estrictamente necesario. Si necesita capturar y volver a generar en una función particular para adjuntar cierta información crucial, está bien, pero capturar todas las excepciones en cada función y con el propósito de adjuntar información ya disponible es simplemente demasiado.


Mira esta pregunta tan . Esto podría estar cerca de lo que estás buscando. No es multiplataforma, pero la respuesta ofrece soluciones para gcc y Visual Studio.


No, es profundamente horrible, y no veo por qué necesita una pila de llamadas en la misma excepción: encuentro el motivo de la excepción, el número de línea y el nombre de archivo del código donde ocurrió la excepción inicial.

Dicho esto, si realmente debe tener un seguimiento de pila, lo que hay que hacer es generar la información de pila de llamadas UNA VEZ en el sitio de lanzamiento de excepción. No hay una sola manera portátil de hacer esto, pero usar algo como http://stacktrace.sourceforge.net/ combinado con una biblioteca similar para VC ++ no debería ser demasiado difícil.


Se deja una excepción que no se maneja para que la función de llamada lo maneje. Eso continúa hasta que se maneja la excepción. Esto sucede con o sin try / catch alrededor de una llamada de función. En otras palabras, si se llama a una función que no está en un bloque de prueba, una excepción que ocurre en esa función se pasará automáticamente a la pila de llamadas. Por lo tanto, todo lo que debe hacer es colocar la función que está más arriba en un bloque de prueba y manejar la excepción "..." en el bloque catch. Esa excepción atrapará todas las excepciones. Por lo tanto, su función superior se verá algo así como

int main() { try { top_most_func() } catch(...) { // handle all exceptions here } }

Si desea tener bloques de código específicos para ciertas excepciones, también puede hacerlo. Solo asegúrese de que ocurran antes del bloque de captura de excepción "...".


Un proyecto más para el soporte de seguimiento de pila: ex_diag . No hay macros, la plataforma cruzada está presente, no hay grandes necesidades de código, la herramienta es rápida, clara y fácil de usar.

Aquí solo necesita envolver los objetos, que deben rastrearse, y se rastrearán si se produce una excepción.


Una solución que puede ser más elegante es construir una macro / clase Tracer. Así que en la parte superior de cada función, escribes algo como:

TRACE()

y la macro se ve algo así como:

Tracer t(__FUNCTION__);

y la clase Tracer agrega el nombre de la función a una pila global en la construcción, y se elimina a sí misma en la destrucción. Entonces esa pila siempre está disponible para el registro o la depuración, el mantenimiento es mucho más simple (una línea) y no genera gastos generales de excepción.

Ejemplos de implementaciones incluyen cosas como http://www.drdobbs.com/184405270 , http://www.codeproject.com/KB/cpp/cmtrace.aspx , y http://www.codeguru.com/cpp/v-s/debug/tracing/article.php/c4429 . Además, las funciones de Linux como esta http://www.linuxjournal.com/article/6391 pueden hacerlo de forma más nativa, como se describe en esta pregunta de Desbordamiento de pila: Cómo generar un seguimiento de pila cuando mi aplicación gcc C ++ falla . El ACE_Stack_Trace de ACE también puede valer la pena.

En cualquier caso, el método de manejo de excepciones es burdo, inflexible y computacionalmente costoso. Las soluciones de construcción de clase / macro son mucho más rápidas y pueden compilarse para compilaciones de lanzamiento si se desea.