try son resueltos que personalizada las instrucciones hacer excepciones excepcion ejercicios como codigo clases catch c++ design exception exception-handling

son - Diseño de clase de excepción c++



excepcion personalizada c++ (6)

Dado que std::nested_exception y std::throw_with_nested están disponibles con C ++ 11 , me gustaría señalar las respuestas en StackOverflow here y here

Esas respuestas describen cómo puede obtener un seguimiento de sus excepciones dentro de su código sin necesidad de un depurador o registro engorroso, simplemente escribiendo un controlador de excepciones adecuado que volverá a lanzar excepciones anidadas.

El diseño de excepciones allí, en mi opinión, también sugiere no crear jerarquías de clases de excepción, sino crear solo una única clase de excepción por biblioteca (como ya se señaló en una respuesta a esta pregunta ).

¿Qué es un buen diseño para un conjunto de clases de excepción? Veo todo tipo de cosas acerca de lo que las clases de excepción deberían y no deberían hacer, pero no un diseño simple que sea fácil de usar y extienda que hace esas cosas.

  1. Las clases de excepción no deben arrojar excepciones, ya que esto podría conducir directamente a la finalización del proceso sin posibilidad de registrar el error, etc.
  2. Es necesario que sea posible obtener una cadena fácil de usar, preferiblemente localizada en su idioma, de modo que haya algo que decirles antes de que la aplicación finalice por sí misma si no puede recuperarse de un error.
  3. Debe ser posible agregar información a medida que la pila se desenrolla, por ejemplo, si un analizador xml no puede analizar un flujo de entrada, para poder agregar que el origen fue de un archivo o de la red, etc.
  4. Los manejadores de excepciones necesitan fácil acceso a la información que necesitan para manejar la excepción
  5. Escriba información de excepción formateada en un archivo de registro (en inglés, de modo que no hay traducciones aquí).

Conseguir que 1 y 4 trabajen juntos es el mayor problema que tengo, ya que cualquier método de formato y de salida de archivos podría fallar.

EDITAR: Entonces, al observar las clases de excepción en varias clases, y también en la pregunta a la que se relaciona Neil, parece ser una práctica común ignorar completamente el ítem 1 (y por lo tanto las recomendaciones de refuerzo), lo cual parece ser una mala idea yo.

De todos modos, pensé que id también publicaría la clase de excepción que estoy pensando en usar.

class Exception : public std::exception { public: //enum for each exception type, which can also be used to determin //exception class, useful for logging or other localisation methods //for generating a message of some sort. enum ExceptionType { //shouldnt ever be thrown UNKNOWN_EXCEPTION = 0, //same as above but has a string that may provide some info UNKNOWN_EXCEPTION_STR, //eg file not found FILE_OPEN_ERROR, //lexical cast type error TYPE_PARSE_ERROR, //NOTE: in many cases functions only check and throw this in debug INVALID_ARG, //an error occured while trying to parse data from a file FILE_PARSE_ERROR, } virtual ExceptionType getExceptionType()const throw() { return UNKNOWN_EXCEPTION; } virtual const char* what()throw(){return "UNKNOWN_EXCEPTION";} }; class FileOpenError : public Exception { public: enum Reason { FILE_NOT_FOUND, LOCKED, DOES_NOT_EXIST, ACCESS_DENIED }; FileOpenError(Reason reason, const char *file, const char *dir)throw(); Reason getReason()const throw(); const char* getFile()const throw(); const char* getDir ()const throw(); private: Reason reason; static const unsigned FILE_LEN = 256; static const unsigned DIR_LEN = 256; char file[FILE_LEN], dir[DIR_LEN]; };

El punto 1 se direcciona ya que todas las cadenas se manejan copiando en un búfer interno de tamaño fijo (truncando si es necesario, pero siempre terminando nulo).

Aunque eso no aborda el punto 3, sin embargo, creo que ese punto es muy probable que tenga un uso limitado en el mundo real de todos modos, y podría abordarse arrojando una nueva excepción si es necesario.


No relacionado directamente con el diseño de una jerarquía de clases de excepción, pero importante (y relacionado con el uso de esas excepciones) es que generalmente debe arrojar por valor y capturar por referencia.

Esto evita los problemas relacionados con la gestión de la memoria de la excepción arrojada (si arrojó punteros) y con el potencial para el corte de objetos (si detecta excepciones por valor).


Un buen diseño no es crear un conjunto de clases de excepción, simplemente cree una por biblioteca, basada en std :: exception.

Agregar información es bastante fácil:

try { ... } catch( const MyEx & ex ) { throw MyEx( ex.what() + " more local info here" ); }

Y los manejadores de excepciones tienen la información que necesitan porque son manejadores de excepciones: solo las funciones en los bloques try pueden causar excepciones, por lo que los manejadores solo necesitan considerar esos errores. Y no deberías estar usando excepciones para el manejo general de errores.

Básicamente, las excepciones deben ser lo más simples posible, un poco como los archivos de registro, que no deberían tener conexión directa.

Esto se ha preguntado antes, creo, pero no puedo encontrarlo ahora.


Use una jerarquía superficial de clases de excepción. Hacer que la jerarquía sea demasiado profunda agrega más complejidad que valor.

Derive sus clases de excepción de std :: exception (o una de las otras excepciones estándar como std :: runtime_error). Esto permite que los manejadores genéricos de excepciones en el nivel superior se encarguen de cualquier excepción que usted no haga. Por ejemplo, podría haber un controlador de excepción que registra errores.

Si esto es para una biblioteca o módulo en particular, es posible que desee una base específica para su módulo (derivada aún de una de las clases de excepciones estándar). Las personas que llaman pueden decidir tomar algo de su módulo de esta manera.

No haría demasiadas clases de excepción. Puede empaquetar muchos detalles sobre la excepción en la clase, por lo que no necesariamente tiene que hacer una clase de excepción única para cada tipo de error. Por otro lado, quieres clases únicas para los errores que esperas manejar. Si está haciendo un analizador sintáctico, es posible que tenga una sola excepción syntax_error con miembros que describan los detalles del problema en lugar de una serie de especiales para diferentes tipos de errores de sintaxis.

Las cadenas en las excepciones están ahí para la depuración. No deberías usarlos en la interfaz de usuario. Desea mantener la IU y la lógica lo más separadas posible, para habilitar cosas como la traducción a otros idiomas.

Sus clases de excepción pueden tener campos adicionales con detalles sobre el problema. Por ejemplo, una excepción syntax_error podría tener el nombre del archivo fuente, el número de línea, etc. En la medida de lo posible, adhiera a los tipos básicos para estos campos para reducir la posibilidad de construir o copiar la excepción para activar otra excepción. Por ejemplo, si tiene que almacenar un nombre de archivo en la excepción, es posible que desee una matriz de caracteres simples de longitud fija, en lugar de std :: string. Las implementaciones típicas de std :: exception asignan dinámicamente la cadena de caracteres utilizando malloc. Si malloc falla, sacrificará la cadena de razón en lugar de arrojar una excepción anidada o colisión.

Las excepciones en C ++ deben ser para condiciones "excepcionales". Entonces, los ejemplos de análisis pueden no ser buenos. Un error de sintaxis encontrado al analizar un archivo puede no ser lo suficientemente especial como para justificar el manejo por excepciones. Diría que algo es excepcional si el programa probablemente no puede continuar a menos que la condición se maneje explícitamente. Por lo tanto, la mayoría de las fallas en la asignación de memoria son excepcionales, pero la entrada incorrecta de un usuario probablemente no lo sea.


Usa herencia virtual . Esta idea se debe a Andrew Koenig. El uso de la herencia virtual de la (s) clase (s) base de su excepción previene problemas de ambigüedad en el sitio de captura en caso de que alguien arroje una excepción derivada de múltiples bases que tienen una clase base en común.

Otros consejos igualmente útiles sobre el sitio de impulso



2: No, no debe mezclar la interfaz de usuario (= mensajes localizados) con la lógica del programa. La comunicación con el usuario debe realizarse en un nivel externo cuando la aplicación se da cuenta de que no puede manejar el problema. La mayoría de la información en una excepción es demasiado un detalle de implementación para mostrar al usuario de todos modos.
3: Use boost.exception para esto
5: No, no hagas esto. Ver 2. La decisión de iniciar sesión siempre debe estar en el sitio de manejo de errores.

No use solo un tipo de excepción. Utilice suficientes tipos para que la aplicación pueda usar un controlador de capturas separado para cada tipo de recuperación de errores necesaria