2009-09-07 14 views
18

Estoy trabajando en una biblioteca que genera informes de dispositivos. La función de miembro generate_report (const std::string& no) puede fallar debido a varios motivos:Excepción vs error-code vs. assert

  1. no válido informe núm.
  2. estado no válido (el report_generator es una FSM)
  3. ningún dispositivo está activo error
  4. durante la generación de informes

¿Cuál es la mejor para estos errores de manejo de errores mecanismo?

  • acaba de regresar true o false
  • código de error de retorno
  • afirmar y registrar
  • excepción (s) tiro
  • cualquier combinación de los anteriores

Parte de la información de contexto: el el flujo de trabajo normal es el siguiente. El usuario activa un dispositivo, elige un informe de una lista y hace clic en "generar".

EDIT: Gracias por las respuestas hasta ahora! Para mí, ahora está claro cuándo usar las afirmaciones y cuándo hacer el manejo de errores. En cuanto a la gestión de errores, los códigos de error y las excepciones tienen pros y contras. Creo que voy por excepciones (y creo cuatro clases para los errores anteriores), pero aún no estoy realmente convencido. Siempre pensé en excepciones de "situaciones inesperadas". Un informe inválido no no es realmente inesperado. ¿Algún consejo? :)

+0

mirada a las preguntas relacionadas http://stackoverflow.com/questions/61219/ debug-assert-vs-specific-throwwn-exceptions, http://stackoverflow.com/questions/1276308/exception-vs-assertion, http://stackoverflow.com/questions/414182/when-to-use-assertion- over-exceptions-in-domain-classes, http://stackoverflow.com/questions/77127/when-to-throw-an-exception, http://stackoverflow.com/questions/17732/when-should-assertions- permanecer en producción de código y tal vez otros. –

+0

Además, observe la etiqueta de manejo de errores. Muchas contribuciones interesantes allí. http://stackoverflow.com/questions/tagged/error-handling –

+0

Muchas gracias, los extrañé por completo porque inicialmente solo busqué preguntas relacionadas con C++ –

Respuesta

2

A menudo es una cuestión de gusto qué estrategia elegir. Digo recoger lo que mejor se integra con los clientes de su biblioteca. Si adoptan una estrategia de excepción, use excepciones. Si están acostumbrados a los códigos de error, quédese con él.

10

afirmar no es la opción correcta. Usa assert cuando tienes un invariante; algo que nunca debería pasar No haga cosas como assert() que un argumento nunca será nulo si es una condición de error y no un invariante.

Si fuera yo, usaría excepciones en la interfaz y, si tuviera que hacerlo, traduciría códigos de error por funciones utilizadas internamente si no usan excepciones. Solo sé consecuente al respecto (y no uses assert para esto).

+0

Un puntero devuelto por nuevo no será nulo, a menos que use "nuevo (nothrow) ". –

+0

¿Estás seguro de eso? Sé que el 'estándar' establece que los nuevos arrojarán una excepción si falla, pero hay una gran cantidad de código heredado que fue escrito mucho antes de que se hiciera esa regla. De todos modos, tal vez fue un ejemplo confuso en este caso, ya que no se aplicará en la mayoría de los casos. –

+0

@Ed Sí, estoy seguro. A menos que utilice un indicador de compilador específico del proveedor que diga "nuevo nunca arroja", el código heredado que verificó si el nuevo nulo devuelto arrojará realmente cuando falle el nuevo (que, por cierto, para las noticias normales, es "nunca"). Por cierto, estoy de acuerdo con tu punto principal. –

1

¡Primero - sea constante!

Segundo:

  • acaba de verdadero/falso no es suficiente. Tiene que combinarse con códigos de error (falso + getLastError por ejemplo).
  • Los códigos de error son rápidos, pero construyen una infraestructura para convertirlos fácilmente en cadenas.
  • assert/log: no, desea que la aplicación pueda reaccionar ante el error
  • las excepciones son más lentas que los códigos de error, pero son más fáciles de programar con un flujo de control difícil.
  • combinaciones
  • : solo se combinan los códigos verdadero/falso + error, para el resto SEA CONSISTENTE lo que significa: no combinar.
3

Recomiendo leer la comunidad de Boost guide [boost.org] para las excepciones y el manejo de errores.

12

Cualquiera de estos tienen diferentes propósitos: vers código

  • error. excepción (es): las excepciones y los códigos de error representan diferentes expresiones idiomáticas de cómo se manejan los códigos de resultado. Las excepciones son más robustas: los códigos de resultado se pueden ignorar o perder. Una biblioteca generalmente debe distinguir fuertemente dónde/qué excepciones se arrojan, y cuándo se usan los códigos de error. En el mejor de los casos, use solo uno de los dos.

  • return true o false: Una especialización de códigos de error. Por lo general, la peor idea - sólo es bueno si no hay más que informar de lo bueno o malo (es decir malloc rendimientos ya sea bueno o malo (= NULL)

  • afirmar y log: Estas son técnicas de depuración, y no debe ser. utiliza como mecanismos de informe a los usuarios/clientes afirma acaba de decir "algo pasó, que no puedo manejar - I Quit".

+0

El comportamiento de assert (en falso) no es necesariamente dejar de fumar. También puede ser para iniciar sesión en un archivo de registro con información como el nombre del archivo fuente, el número de línea, un volcado de pila y el texto de confirmación (que puede contener valores de algunas variables). Otro comportamiento es el comportamiento predeterminado para las aplicaciones de Windows creadas con Visual Studio: se muestra un cuadro de diálogo con botones para abortar, volver a intentar o ignorar. –

+0

Sí, una afirmación no tiene que salir, pero ese es el caso típico. Uso mis propias afirmaciones que ofrecen exactamente las posibilidades que mencionas (continuar, salir, etc.). Según mi experiencia, en la mayoría de los casos no hay una salida segura ya que los errores se repiten continuamente. –

1
  • registro debe utilizarse si usted no tiene acceso a un terminal para. produciendo/leyendo informes de errores
  • return True/Fals e debe combinarse con códigos de error. Ejemplo: Una función devuelve True en caso de éxito, False en caso de error, y establece una variable (global o parámetro, su elección) con un código de error/descripción apropiado.
  • excepciones: en mi opinión, es bueno combinarlos con el registro y la recuperación elegante de los errores. Si esto no es posible, también puede recurrir a códigos de error, ya que las excepciones no proporcionan beneficios adicionales.
  • assert(): Como otros han señalado compila en compilaciones de versiones, así que dispara a voluntad.

2c

+0

Er, does not assert() compila en versiones de lanzamiento? – JBRWilkinson

+0

Es posible que desee buscar la documentación. assert() de compila en versiones de lanzamiento. – MSalters

2

¿Qué tan confiables son los dispositivos que está informando sobre?

Lo pregunto porque para una clase grande de dispositivos no conectados, no conectados, sin baterías, ocupados haciendo otra cosa, etc. son estados bastante normales.

Si este es el caso, preferiría devolver un código de estado (tenga en cuenta que no hay un código de error) si el dispositivo no está disponible de alguna manera.

Si, por otro lado, considera que estos dispositivos son muy confiables y realmente es excepcional que no respondan, el manejo de excepciones puede ser el camino a seguir.

Realmente no importa que el mutch como 'excepciones' sea realmente una forma elegante de codificar 'if (x! = 0) {goto error_routine; }, pero, personalmente, prefiero el manejo de excepciones para tratar situaciones excepcionales, no eventos de rutina como end_of_file.

+0

Buen punto. Creo que la pregunta es ¿cuál es una situación excepcional? P.ej. si quiero generar el informe n. ° 42 que no existe, o generar un informe mientras no se selecciona ningún dispositivo. –

5

excepciones en comparación con los códigos de verdadero/falso y errores tienen varias ventajas importantes:

  • excepciones no pueden ser ignorados. Si su código arroja una excepción, la persona que llama debe atraparla para evitar recibir una excepción no controlada.
  • Las excepciones se pueden manejar en un nivel más alto que la persona que llama inmediatamente. Si utiliza códigos de error, puede terminar en situaciones en las que en todas las capas de su aplicación tenga que verificar los errores y devolverlos a la persona que llama.

Las afirmaciones se utilizan para expresar cosas como condiciones previas en su código y con suerte descubrirán errores durante el desarrollo. Sin embargo, no debe confiar en las afirmaciones de su código de publicación y, por motivos de rendimiento, las afirmaciones normalmente se eliminan del código de publicación.

+1

El peligro de las excepciones en C++ es que puede terminar con fugas de memoria difíciles de seguir al dejar un marco de pila que libera memoria. – carl

2

Iré contra la corriente y sugiero códigos de error y excepciones, pero solo porque está creando una biblioteca. Como dices que estás haciendo una biblioteca, supongo que la biblioteca estará disponible para el código escrito por personas sobre las que no tienes control. Por lo tanto, hacer que el código sea compatible con diferentes compiladores y posiblemente incluso con idiomas es algo bueno.

Así que codificaría una biblioteca de excepciones de C++ y proporcionaría archivos de encabezado que detallaran sus clases de excepción. También codificaría una interfaz C que maneja las excepciones para el usuario. Ahora el usuario puede enlazar contra el que jamás interfaz es apropiado:

#ifdef __cplusplus__ 
void generate_report(const std::string& rep_number, ostream& output); 

extern "C" 
#endif 
int generate_report(const char* rep_number, const char* outputfilename, 
        int* error_code, char* error_text, int max_error_text_len); 

La aplicación C llama a la implementación en C++:

extern "C" 
int generate_report(const char* rep_number, const char* outputfilename, 
        int* error_code, char* error_text, int max_error_text_len) 
{ 
    ofstream os; 
    try { 
     os.open(outputfilename, IOS_WRITE); 
     generate_report(rep_number, os); 
     os.close(); 
     return TRUE; 
    } catch (base_exception& e) { 
     os.close(); 
     if (error_code) *error_code = e.error_code(); 
     if (error_text) strncpy(error_text, e.str(), max_error_text_len); 
     return FALSE; 
    } 
} 
Cuestiones relacionadas