clase - format exception c++
Confundido sobre std:: runtime_error vs. std:: logic_error (5)
Hace poco vi que la biblioteca de boost program_options arroja un logic_error
si la entrada de la línea de comando no fue analizable. Eso desafió mis suposiciones sobre logic_error
vs. runtime_error
.
Supuse que los errores lógicos ( logic_error
y sus clases derivadas) eran problemas que resultaban de fallas internas para adherirse a las invariantes del programa, a menudo en forma de argumentos ilegales para las API internas. En ese sentido, son en gran parte equivalentes a ASSERT, pero destinados a ser utilizados en código liberado (a diferencia de ASSERT, que generalmente no se compilan en código publicado). Son útiles en situaciones donde no es factible integrar componentes de software separados en compilaciones de depuración / prueba o las consecuencias de una falla son tales que es importante dar retroalimentación en tiempo de ejecución sobre la condición invariable no válida para el usuario.
Del mismo modo, pensé que runtime_error
s resultaba exclusivamente de condiciones de tiempo de ejecución fuera del control del programador: errores de E / S, entrada de usuario no válida, etc.
Sin embargo, program_options es obviamente usado (¿sobre todo?) Como un medio para analizar la entrada del usuario final, por lo que bajo mi modelo mental ciertamente debería arrojar un runtime_error
en el caso de una mala entrada.
¿Dónde estoy equivocado? ¿Estás de acuerdo con el modelo de impulso del tipeo de excepciones?
Desde un punto de vista estándar puro, tienes razón. program_options debe lanzar clases derivadas de runtime_error
o logic_error
dependiendo de si el error es en tiempo de ejecución o es lógico. (No revisé el código actual para determinar dicha clasificación de idea para las excepciones actuales).
Desde un punto de vista práctico, aún no he visto el código C ++ que toma decisiones útiles en función de si la excepción es logic_error
o runtime_error
. Después de todo, la única razón por la que lanzaría un logic_error
en lugar de dejar que assert File sea es si desea intentar recuperar de alguna manera, y eso no es diferente de la recuperación de un error de tiempo de ejecución. Personalmente, veo logic_error
vs. runtime_error
la misma manera que las excepciones comprobadas en Java, teóricamente agradable, pero no útil en la práctica. Lo que significa que, tal vez, solo haré que program_options::error
derive from exception
. Es decir, cuando encuentre ese "tiempo libre", todo el mundo sigue hablando.
El borrador actual del Estándar C ++ 0x dice (cláusula 19.2):
1) En el modelo de error reflejado en estas clases (es decir, los tipos de excepción), los errores se dividen en dos grandes categorías: errores de lógica y de tiempo de ejecución.
2) La característica distintiva de los errores lógicos es que se deben a errores en la lógica interna del programa. En teoría, son prevenibles.
3) Por el contrario, los errores de tiempo de ejecución se deben a eventos más allá del alcance del programa. No pueden predecirse fácilmente de antemano.
Junto con las citas citadas en una de las otras respuestas, esto explica por qué Boost.ProgramOptions arroja un std :: logic_error para los errores prevenibles causados por un "error presumiblemente detectable antes de que el programa se ejecute".
El usuario podría verificar que el archivo existe, ejecutar el programa y, de repente, aprender que el archivo ha sido eliminado. Es por eso que un problema de E / S siempre es un runtime_error
. Los problemas de estado son runtime_errors, incluso si la persona que llama pudo haber verificado, ya que otro hilo podría causar el problema.
logic_error
es cuando los argumentos de una función son incorrectos. Es solo para cosas que podrían haber sido atrapadas antes con una verificación de tipo más fuerte.
Entonces, "archivo faltante" es un runtime_error
, pero "nombre de archivo formateado incorrectamente" es un logic_error
.
Técnicamente, un error lógico dentro de una función es también un logic_error
, pero si eres lo suficientemente inteligente como para probarlo dentro de tu propia función, deberías ser lo suficientemente inteligente como para evitarlo en primer lugar.
En este caso, creo (al menos en su mayor parte) tienes razón y está mal. El estándar describe logic_error
como:
La clase logic_error define el tipo de objetos arrojados como excepciones para informar errores presumiblemente detectables antes de que se ejecute el programa, como violaciones de precondiciones lógicas o invariantes de clase.
Un argumento de línea de comando que no se puede analizar no parece encajar muy bien.
Por el contrario, describe runtime_error
como:
La clase runtime_error define el tipo de objetos lanzados como excepciones para informar errores presumiblemente detectables solo cuando el programa se ejecuta.
Eso parece ser un mejor ajuste.
IMO,
std::logic_error
es lanzado intencionalmente por un usuario de la lógica del programa C ++. Predicho por un programa de usuario.std::runtime_error
es lanzado por un tiempo de ejecución de C ++ (o parte central del lenguaje ...) para abstraer los errores de nivel inferior. Simplemente sucede sin ninguna intención sin la participación de ningún código de usuario.