sistema santillana pleno plataforma pagos myon mls30 lms30 compartir como alumnos acceder c++ exception logging raii

c++ - santillana - sistema uno pagos



¿Cómo debe uno iniciar sesión cuando se activa una excepción? (1)

No tengo ningún comentario sobre tu método, ¡pero parece interesante! Tengo otra manera en la que también podría funcionar para lo que quieres, y podría ser un poco más general. Sin embargo, requiere lambdas de C ++ 11, lo que podría o no ser un problema en su caso.

Es una plantilla de función simple que acepta una lambda, la ejecuta y captura, registra y vuelve a lanzar todas las excepciones:

template <typename F> void try_and_log (char const * log_message, F code_block) { try { code_block (); } catch (...) { log (log_message); throw; } }

La forma en que lo usa (en el caso más simple) es así:

try_and_log ("An exception was thrown here...", [&] { this_is_the_code (); you_want_executed (); and_its_exceptions_logged (); });

Como dije antes, no sé cómo se compara con su propia solución. Tenga en cuenta que la lambda está capturando todo desde su alcance envolvente, lo cual es bastante conveniente. También tenga en cuenta que en realidad no lo he intentado, por lo que pueden surgir errores de compilación, problemas lógicos y / o guerras nucleares.

El problema que veo aquí es que no es fácil incluir esto en una macro y esperar que tus colegas escriban las partes [=] { y } correctamente y que todo el tiempo sea demasiado.

Para propósitos de envoltura y prueba de TRY_AND_LOG_BEGIN , probablemente necesitará dos macros: un TRY_AND_LOG_BEGIN para emitir la primera línea hasta la llave de apertura para la lambda y un TRY_AND_LOG_END para emitir la llave de cierre y el paréntesis. Al igual que:

#define TRY_AND_LOG_BEGIN(message) try_and_log (message, [&] { #define TRY_AND_LOG_END() })

Y los usa así:

TRY_AND_LOG_BEGIN ("Exception happened!") // No semicolons here! whatever_code_you_want (); TRY_AND_LOG_END ();

¡Lo cual, según su perspectiva, es una ganancia neta o una pérdida neta! (Personalmente prefiero la llamada de función directa y la sintaxis lambda, lo que me da más control y transparencia.

Además, es posible escribir el mensaje de registro al final del bloque de código; simplemente cambie los dos parámetros de la función try_and_log .

En un programa que escribí recientemente, quería iniciar sesión cuando mi código de "lógica de negocios" desencadenaba una excepción en API de proyectos o de terceros. (Para aclarar, quiero iniciar sesión cuando el uso de una API provoca una excepción. Puede tratarse de muchos fotogramas por encima del throw real, y puede haber muchos fotogramas debajo de la catch real (donde puede producirse el registro de la carga de excepción)) hizo lo siguiente:

void former_function() { /* some code here */ try { /* some specific code that I know may throw, and want to log about */ } catch( ... ) { log( "an exception occurred when doing something with some other data" ); throw; } /* some code here */ }

En resumen, si se produce una excepción, cree una cláusula catch-all, registre el error y vuelva a lanzar. En mi mente esto es seguro. Sé que en general todo se considera malo, ya que uno no tiene ninguna referencia a la excepción para obtener información útil. Sin embargo, voy a volver a lanzarlo, para que no se pierda nada.

Ahora, por sí solo estaba bien, pero algunos otros programadores modificaron este programa y terminaron violando lo anterior. Específicamente, pusieron una gran cantidad de código en el try-block en un caso, y en otro eliminaron el ''throw'' y colocaron un ''return''.

Ahora veo que mi solución era frágil; no fue a prueba de modificación en el futuro.

Quiero una mejor solución que no tenga estos problemas.

Tengo otra solución potencial que no tiene el problema anterior, pero me pregunto qué piensan los demás al respecto. Utiliza RAII, específicamente un objeto de "Salida con alcance" que desencadena implícitamente si std::uncaught_exception no es verdadero en la construcción, pero es cierto en la destrucción:

#include <ciso646> // not, and #include <exception> // uncaught_exception class ExceptionTriggeredLog { private: std::string const m_log_message; bool const m_was_uncaught_exception; public: ExceptionTriggeredLog( std::string const& r_log_message ) : m_log_message( r_log_message ), m_was_uncaught_exception( std::uncaught_exception() ) { } ~ExceptionTriggeredLog() { if( not m_was_uncaught_exception and std::uncaught_exception() ) { try { log( m_log_message ); } catch( ... ) { // no exceptions can leave an destructor. // especially when std::uncaught_exception is true. } } } }; void potential_function() { /* some code here */ { ExceptionTriggeredLog exception_triggered_log( "an exception occurred when doing something with some other data" ); /* some specific code that I know may throw, and want to log about */ } /* some code here */ }

Quiero saber:

  • técnicamente, ¿funcionaría esto de manera robusta? Inicialmente parece funcionar, pero sé que hay algunas advertencias sobre el uso de std::uncaught_exception .
  • ¿Hay alguna otra manera de lograr lo que quiero?

Nota : He actualizado esta pregunta. Específicamente, yo he:

  • se agregó la try / catch que inicialmente faltaba, alrededor de la función-llamada de log .
  • se agregó el seguimiento del estado std::uncaught_exception en la construcción. Esto protege contra el caso en el que se crea este objeto dentro de un bloque ''try'' de otro destructor que se desencadena como parte del desenrollado de la pila de excepción.
  • corrigió la nueva ''función_potencial'' para crear un objeto nombrado , no un objeto temporal como antes.