2011-01-20 10 views
18

Para un código de biblioteca, ¿es una mejor práctica crear y lanzar una clase de excepción personalizada (library :: Exception), o simplemente lanzar excepciones estándar (runtime_error, invalid_argument, etc.)?¿Excepción estándar o personalizada en C++?

+0

posible duplicado de [¿Debo heredar de std :: exception?] (Http://stackoverflow.com/questions/1669514/should-i-inherit-from-stdexception) – timday

+1

No creo que esas preguntas sean duplicadas . Una pregunta sobre excepciones y otra sobre clases base de excepciones. –

Respuesta

27

Por lo general, es mejor especializar (heredar) una excepción estándar y lanzarla.

De esta forma, será posible detectarlo como una excepción genérica simplemente al detectar un std::exception, pero también podría detectar específicamente su tipo de excepción personalizado si necesita un código más especializado.

Consulte también este artículo C++Faq sobre qué arrojar.

+4

Básicamente no hay mejor respuesta que esta. Cree sus propias clases de excepción personalizadas que heredan de std :: runtime_error (que ya hereda de std :: exception). De esta manera, sus clientes tienen la opción de detectar sus excepciones específicas, o simplemente atrapar std :: exception o std :: runtime_error. – Mephane

+0

+1 Esto también tiene el beneficio adicional de darle la oportunidad de agregar apéndices a la excepción lanzada. Puede incluir más información, como el nombre de archivo y el número de línea del código que generó la excepción. Ver esto para un ejemplo: http://stackoverflow.com/questions/4595350/c-declare-static-variable-in-function-argument-list-generate-keys-for-lines/4595976#4595976 –

+1

Yo diría Depende de la situación. En la base de código que mantengo, hay muy pocos errores que quiera detectar por excepción. O tiene una excepción muy específica para tratar, o los deja pasar a la interfaz de usuario. Por lo tanto, no es necesario en muchos casos para una jerarquía de excepciones muy estructurada, y las clases estándar (quizás aumentadas con unas pocas clases personalizadas) hacen el trabajo limpiamente. Tirar 'std :: invalid_argument' cuando el argumento no es válido, lanzar' logic_error' o 'runtime_error' genéricamente, y hacer excepciones personalizadas para cosas como' bad_my_custom_dynamic_cast'. –

2

En mi humilde excepción personalizada. Los clientes de su biblioteca apreciarán esto. Él sabrá qué es exactamente lo que plantea la excepción.

2

Por experiencia, es raro que necesite más que unas pocas clases de excepciones.

En la mayor parte de mi código (principalmente numéricos -. Si lo hace por ejemplo IO, la situación es diferente), lanzo Excepciones estándar (runtime_error, invalid_argument, ...), ya que tienden a indicar algo que no puede ser fácilmente recuperado de (excepto quizás invalid_argument), y que probablemente no sea capturado por el código de usuario (excepto tal vez en el nivel superior para arrojar un cuadro de mensaje al usuario).

Si hay alguna excepción que esté destinada a ser capturada por un código de usuario típico, p. Ej. bad_custom_cast, o bad_market_data_identifier, en lugar de borbotear a main (como una falla en una rutina numérica, o bad_alloc), realizo una clase personalizada. Pero esto es bastante raro en realidad.

7

Generalmente debe lanzar instancias de clases en el encabezado stdexcept o subclases de las mismas. La clase que tiene sentido depende del problema específico. Creo que arrojar instancias de "clases de categoría" std::logic_error y std::runtime_error rara vez es útil, ya que no tienen un significado inherente; que se utilizan para distinguir las dos situaciones principales que se pueden producir excepciones:

  • Las subclases de std::logic_error debe ser lanzado por una función de si se llama, pero no se cumplen todas las condiciones previas. La excepción es la culpa de la persona que llama, ya que no ha podido proporcionar las condiciones previas necesarias. Para esta categoría, generalmente debe elegir entre arrojar y comportamiento indefinido; se trata de un compromiso entre la robustez y eficiencia (por ejemplo std::vector::at() vs std::vector::operator[] Estas excepciones a menudo no pueden ser manipulados;. que son el resultado de errores en el programa

  • Las subclases de std::runtime_error debe ser tirado por una función de si todo. se cumplen las condiciones pero la función no puede cumplir con las condiciones posteriores o rompe invariantes por razones ajenas al control del programa (p. ej., no existe un archivo, la conexión de red se pierde o no hay suficiente memoria disponible). Por lo general, estas excepciones deben ser manejado.

creo que la lógica disponibles clases de error (p. invalid_argument) a menudo son lo suficientemente buenos, porque si se generan, el código generalmente debe ser reparado, y no hay razón para rutinas de manejo elaboradas. Por otro lado, las clases de error en tiempo de ejecución en la biblioteca estándar son, por su naturaleza, mucho menos flexibles y cubren principalmente las áreas donde la biblioteca estándar en sí tiene que arrojar excepciones.Para su aplicación, casi siempre debe heredar de estas clases de error de tiempo de ejecución. Por ejemplo, una clase que administra el recurso del sistema operativo X debe arrojar un X_creation_error que hereda de std::runtime_error si el constructor no puede asignar el recurso.

La herencia virtual múltiple a menudo es útil con clases de excepción. Puede heredar de std::runtime_error u otras clases stdexcept, de alguna "clase de marcador" específica de su biblioteca y de boost::exception para obtener los beneficios adicionales de Boost.Exception library. Se recomienda encarecidamente el tutorial Boost.Exception, especialmente Exception types as simple semantic tags y Using virtual inheritance in exception types.

Cuestiones relacionadas