2011-08-07 9 views
11

Estoy escribiendo algunas funciones de la biblioteca que necesitan hacer algunos informes de errores. Quiero usar excepciones en lugar de valores devueltos.C++ Excepciones; int o std :: excepción?

Escribí mis funciones que arroja excepciones int.

Ej:

if(strm->atEnd()){ 
    // unexpected end of stream 
    throw -2; 
} 

Mi pregunta es, es este método de acuerdo? ¿O debería lanzar una excepción derivada de std :: exception?

¿De qué manera está lanzando una std :: exception better? (Además de ser capaz de usar catch (std :: exception & e))

Está lanzando int exceptions ¿mala práctica? (todos los valores de throw int están documentados en los comentarios de doxygen)

No encuentro ningún motivo sobre por qué (en este caso) debo arrojar un objeto.

+2

puedo hacer eso cuando estoy hackeando cosas juntos. Pero cuando termine, siempre generará un objeto de excepción real (derivado de std :: rtuntime_error). Como esto simplifica todo mi código de manejo de excepciones. Digamos que captas eso en main(). ¿Cómo se sabe qué componente generó el error -345678? –

Respuesta

0

¿Por qué no se hace esto:

if(strm->atEnd()){ 
    // unexpected end of stream 
    throw std::exception("-2"); 
} 

throw -2 es malo porque el tipo de -2 es ni std::exception ni deriva de std::exception.

O mejor debería escribir su propia clase como:

class FileException : std::exception 
{ 
     //... 
}; 

Y luego

throw FileException("Unexpected end of stream"); 

que es más fácil de leer.

+2

Porque no tiene sentido? – Johnsyweb

+4

Personalmente he dejado de derivar mis propias clases de excepción (solo uso std :: runtime_error); A menos que exista una situación específica que pueda detectar y corregir con la excepción especializada. Si todo lo que puedo hacer es registrar, entonces std :: runtime_error suele ser la elección perfecta. Nota: FileException probablemente debería derivar de std :: runtime_error (como std :: exception no tiene un constructor que tome un mensaje de error) nota secundaria: MS tiene una extensión no estándar para std :: exception que le permite pasar un mensaje de error . –

+0

¿Por qué demonios mantendría el "-2" pero lo puso como la excepción? –

3

Debe lanzar una excepción derivada de std::exception, p. Ej. std::runtime_error.

La mayoría del código existente asume que una excepción normal de C++ es std::exception, y cualquier otra cosa es una "excepción difícil" para propagarse a un nivel de control muy alto, como main.

Por ejemplo, es probable que el código existente no pueda registrar ningún mensaje razonable para su int. Simplemente será "tipo de excepción desconocida".

Saludos & HTH.,

16

usted debe lanzar una excepción basada en std::exception.

throw std::runtime_error("unexpected end of stream") 

Basta pensar lo fácil que es para catch, registro, etc. . ¡También le permite eliminar un comentario inútil y eliminar un número mágico de su código!

Este mensaje se puede enviar al usuario final para darles la esperanza de solucionar el problema. No pueden leer los comentarios en su código (no leerán su resultado de Doxygen) y es poco probable que sepan qué significa '-2'.

7

Mi pregunta es, ¿este método está bien?

Piense en la legibilidad. No sería

throw CUnexpectedEndOfStream(); 

ser más fácil de leer que

throw -2 

?

Y en muchos casos no ver una instancia de CUnexpectedEndOfStream arrojado en el depurador significa TONELADAS más de -2. Eso sin mencionar que CUnexpectedEndOfStream podría almacenar montones de información útil sobre el problema, como decir el archivo que no se pudo leer y tal vez más información sobre la naturaleza del problema.

¿O debería arrojar una excepción derivada de std :: exception?

Heredar de std::exception puede ser útil si así es como elige organizar sus otras excepciones. Es una clase base conveniente que el código del cliente puede usar. Además, dependiendo de la excepción, es posible que desee utilizar std::runtime_error.

Está lanzando int excepciones malas prácticas? (todos los valores throw int están documentados en los comentarios doxygen)

¿Quién dijo que era una mala práctica? Lanzar excepciones es una gran manera de manejar situaciones excepcionales. La mayoría de las excepciones que arrojo son por algo que el código del cliente podría haber evitado haciendo lo que se suponía que debía hacer: el usuario de mi código violó el contrato. Pero existen muchos otros casos no normales excepcionales, como errores de SO, discos que se llenan, etc. Todo lo que no forma parte del flujo normal de sus programas. Más importante aún, ya que no son parte del flujo normal de su programa, no necesita preocuparse por el rendimiento.

Como ejemplo, una vez utilicé excepciones para desencadenar que se produjera una falla en el análisis del mensaje. Sin embargo, descubrí que estos errores de análisis se producían con frecuencia hasta el punto en que comencé a manejar excepciones y solucionar el problema de entrada y repaso. Después de un tiempo, me di cuenta de que una solución más legible sería solucionar el problema directamente en el código de análisis y dejar de tratarlo como un caso excepcional. Todo el código que tomaba las decisiones de análisis fue puesto nuevamente en un lugar y no estaba lanzando excepciones como un marinero borracho arroja palabras de maldición.

+0

ISTM pregunta específicamente acerca de arrojar *** int excepciones ***. –

9

La excepción es para comportamiento excepcional. ¡Son lo último que debes preocuparte por optimizar!

Donald Knuth dijo:

Debemos olvidarnos de pequeñas eficiencias, por ejemplo alrededor del 97% del tiempo: la optimización prematura es la raíz de todo mal

También, un objeto como excepción puede llevar información sobre el error.

Por ejemplo, tiene una excepción que significa que un archivo no se puede leer. Si lanza una excepción de objeto, el objeto puede llevar el nombre del archivo, que no puede tener con ints.

Si el origen de la excepción es desconocido (en lo profundo de su pila) y nadie lo detecta, será más fácil depurar el programa si la excepción es un objeto con la información adecuada.

-6

En teoría, siempre puede arrojar excepciones complejas, pero en la mayoría de los casos no es necesario.

Mi pregunta es, ¿este método está bien?

Sí y No. En teoría, podría hacerlo por todos los medios, pero no es una buena práctica (lea a continuación). Sin embargo, si aún lo hace, al menos sugeriría #define los códigos de error para una mejor legibilidad.

#define UNEXPECTED_END_OF_STREAM -2 

if(strm->atEnd()){ 
    // unexpected end of stream 
    throw UNEXPECTED_END_OF_STREAM; 
} 

Es muy raro que tirar números -ve como códigos de error/excepción y lo más probable es que fruncir el ceño sobre. De hecho, las personas fruncen el ceño lanzando la excepción int, aunque hará exactamente lo que usted quiere hacer (en la mayoría de los casos al menos), es decir, detectar un error.

La excepción más común que lanzo es std :: runtime_error ("Mi error") `que es un disfraz para arrojar una excepción de cadena simple. En la mayoría de los casos, las excepciones básicas son todo lo que necesitamos, detectar el error y regresar.

Recuerde que no importa qué tipo de excepción arroje siempre obtendrá el beneficio del bloque try-catch que es realmente el corazón del manejo de excepciones. Lo mismo es cierto si lanza una excepción int. Me imagino que el int indicará probablemente el código de error. En algún momento esto puede ser necesario, por ejemplo, si está utilizando excepciones en las partes internas de un dll, pero desea devolver los códigos de error al mundo exterior. Creo que su pregunta realmente se reduce a este problema, ¿puedo lanzar una excepción int y debería?

También tenga en cuenta que puede hacerlo, pero lanzar una excepción int no es lo más elegante. ¿Por qué? Debido a que int es un tiempo de datos primitivo y desea pensar orientado a objetos en C++, entonces debería arrojar un objeto mejor. Esto puede significar que tendrá que encapsular el código de error int en un objeto y lanzar ese objeto. Quizás cuando lo hagas, sería una buena idea agregar una cadena que describa el error también. Esto es lo que hice en el pasado. Obtuve mi clase de excepción desde std::runtime_error y agregué código de error.

class my_error : public std::runtime_error 
{ 
public: 
    my_error(std::string const& msg, int code); 
    virtual ~my_error(void); 

    // the error code which you want to throw 
    int errCode; 
}; 

Ahora, cuando usted quiere lanzar un/a errores código de excepción, lo hace:

throw my_error("this is my own error!", UNEXPECTED_END_OF_STREAM); 
+1

-1: Utter hogwash. Estás perjudicando activamente a la comunidad C++ publicando consejos como este. –

+2

¡Qué fracaso épico! – Puppy

+0

@DeadMG ¿Qué tiene de malo? – zar

Cuestiones relacionadas