try tipos son que programacion personalizadas las lanzamiento instrucciones excepciones error dev catch c++ stl exception multiple-inheritance

c++ - son - tipos de excepciones en programacion



Excepciones personalizadas en C++ (2)

He estado tratando de hacer algunas clases de excepción personalizadas para una biblioteca de C ++ en la que estoy trabajando. Estas excepciones personalizadas capturan información adicional, como el archivo, el número de línea, etc., necesaria para la depuración, si por alguna razón, al probar una excepción, no se encuentra en el lugar correcto. Sin embargo, la mayoría de las personas parecen recomendar la herencia de la clase std :: exception en la STL, con lo que estoy de acuerdo, pero me preguntaba si sería mejor usar la herencia múltiple para heredar de cada una de las clases derivadas de std :: exception (por ejemplo, .std :: runtime_error) y una clase de excepción personalizada, como en el siguiente código?

Otra cosa, ¿cómo hace uno para copiar constructores y operadores de asignación en clases de excepción? ¿Deben ser discapacitados?

class Exception{ public: explicit Exception(const char *origin, const char *file, const int line, const char *reason="", const int errno=0) throw(); virtual ~Exception() throw(); virtual const char* PrintException(void) throw(); virtual int GetErrno(void); protected: std::string m_origin; std::string m_file; int m_line; std::string m_reason; int m_errno; }; class RuntimeError: public virtual std::runtime_error, public Exception{ public: explicit RuntimeError(const char *origin, const char *file, const int line, const char *reason="", const int errno=0) throw(); virtual ~RuntimeError() throw(); };


Me preguntaba si sería mejor usar la herencia múltiple para heredar de cada una de las clases derivadas std :: exception

Tenga en cuenta que esto es un problema, debido al hecho de que las excepciones en la biblioteca estándar se derivan no virtualmente entre sí. Si introduce la herencia múltiple, obtendrá la temible jerarquía de excepción de diamante sin herencia virtual y no podrá capturar excepciones derivadas de std::exception& , ya que su clase de excepción derivada contiene dos subobjetos de std::exception , lo que hace que std::exception una "clase base ambigua".

Ejemplo concreto:

class my_exception : virtual public std::exception { // ... }; class my_runtime_error : virtual public my_exception , virtual public std::runtime_error { // ... };

Ahora my_runtime_error deriva (indirectamente) de std::exception dos veces, una vez a través de std::run_time_error y una vez a través de my_exception . Dado que el primero no deriva de std::exception virtualmente, esto

try { throw my_runtime_error(/*...*/); } catch( const std::exception& x) { // ... }

no funcionará

Editar:

Creo que he visto el primer ejemplo de una jerarquía de clases de excepciones que involucra a MI en uno de los libros de Stroustrup, por lo que llegué a la conclusión de que, en general, es una buena idea. Que las excepciones de la biblioteca estándar no se derivan virtualmente de las demás, lo considero un fracaso.

La última vez que diseñé una jerarquía de excepciones, usé MI muy extensamente, pero no derivé de las clases de excepciones de la biblioteca estándar. En esa jerarquía, había clases de excepciones abstractas que usted definió para que sus usuarios pudieran capturarlas, y las clases de implementación correspondientes, derivadas de estas clases abstractas y de una clase base de implementación, que realmente lanzaría. Para hacer esto más fácil, definí algunas plantillas que harían todo el trabajo duro:

// something.h class some_class { private: DEFINE_TAG(my_error1); // these basically define empty structs that are needed to DEFINE_TAG(my_error2); // distinguish otherwise identical instances of the exception DEFINE_TAG(my_error3); // templates from each other (see below) public: typedef exc_interface<my_error1> exc_my_error1; typedef exc_interface<my_error2> exc_my_error2; typedef exc_interface<my_error3,my_error2> // derives from the latter exc_my_error3; some_class(int i); // ... }; //something.cpp namespace { typedef exc_impl<exc_my_error1> exc_impl_my_error1; typedef exc_impl<exc_my_error2> exc_impl_my_error2; typedef exc_impl<exc_my_error3> exc_impl_my_error3; typedef exc_impl<exc_my_error1,exc_my_error2> // implements both exc_impl_my_error12; } some_class::some_class(int i) { if(i < 0) throw exc_impl_my_error3( EXC_INFO // passes ''__FILE__'', ''__LINE__'' etc. , /* ... */ // more info on error ); }

Mirando hacia atrás en este momento, creo que podría haber hecho que la plantilla de clase exc_impl derive de std::exception (o cualquier otra clase en la jerarquía de excepciones de la exc_impl , pasada como parámetro de plantilla opcional), ya que nunca deriva de ninguna otra instancia de exc_impl . Pero en aquel entonces esto no era necesario, por lo que nunca se me ocurrió.


Debes probar boost::exception

El propósito de Boost Exception es facilitar el diseño de jerarquías de clase de excepción y ayudar a escribir código de manejo de excepciones y de informe de errores.

Admite el transporte de datos arbitrarios al sitio de captura, que de otro modo es complicado debido a los requisitos de no lanzar (15.5.1) para los tipos de excepción. Los datos se pueden agregar a cualquier objeto de excepción, ya sea directamente en la expresión de lanzamiento (15.1), o en un momento posterior a medida que el objeto de excepción se propaga hacia la pila de llamadas.

La capacidad de agregar datos a los objetos de excepción después de que se hayan pasado para lanzarlos es importante, porque a menudo parte de la información necesaria para manejar una excepción no está disponible en el contexto donde se detecta el error.

Boost Exception también admite la copia de objetos de excepción al estilo N2179, implementada de forma no intrusiva y automática mediante la función boost :: throw_exception.