2012-07-02 13 views

Respuesta

13

Ese sitio es estúpido, y enseña mal diseño.

Si se lanza int o char*, entonces tendrá que atraparlo usando int o char* solamente. Puede calificarlo con const.

Si arroja std::runtime_error, puede capturarlo usando std::runtime_error const &, o su clase base std::exception const &.

¿Qué tiene de bueno esto?

El bueno de esto es que si se arroja una excepción el uso de una clase que se deriva en última instancia std::exception, entonces se puede escribir sólo UN catch bloque que acepta la excepción, ya que std::exception const&, independientemente de which derived class se utiliza para lanzar una excepción.

Aquí está un ejemplo:

void f(A & a) 
{ 
    if (!check_arg(a)) 
    { 
      throw std::invalid_argument("invalid argument"); 
    } 
    else if (!check_size(a)) 
    { 
      throw std::length_error("invalid length");    
    } 

    //code 
    if(someCondition) 
    { 
      //assume your_own_defined_exception's ultimate base is std::exception 
      throw your_own_defined_exception("condition unsatisfied");       
    } 
    //... 

} 

Ahora la parte interesante:

try 
{ 
     f(a); //it can throw exception of at least 3 types! 
} 
catch(std::exception const &e) //all types can be caught by just one catch! 
{ 
    //handle this case 
} 

Lo bueno es que usted no es requiere escribir trescatch bloques sólo porque f() podría lanzar tres diferentes tipos de excepción. Usted puede escribir más de un catch para manejarlos de manera diferente si eso lo beneficia de alguna manera. Pero el punto a tener en cuenta aquí es: no ¡un requisito!

En resumen, puede aprovechar la jerarquía de clases.

+0

Básicamente, naturalmente, permite que la herencia simplifique el diseño del manejo de errores. Muy elegante. Si defino mi propia clase de excepción y lo hago de esa manera, puedo producir los mismos resultados, ¿sí? –

+3

@StevenLu Si obtiene su propia clase de excepción, reinventa la rueda y potencialmente descifra el código que depende de la captura de std :: exception. Si bien esto puede estar bien para sus proyectos personales, hace que su código sea difícil de distribuir a otros. El enfoque estándar es tener una jerarquía de excepciones específica de la aplicación que subclases 'std :: exception'. Por ejemplo, haga que todas sus excepciones sean subclases de 'StevenLuException', que es una subclase de' std :: exception'. – sfstewman

+0

@StevenLu: si su clase de excepción deriva en última instancia de 'std :: exception', entonces sí, es un diseño elegante. Ver la * tercera * excepción llamada 'your_own_defined_exception' en mi código de ejemplo. Dije que tiene que derivarse de 'std :: exception' en última instancia. – Nawaz

1

Principalmente porque cuando trabajas con otras personas tienes que acordar qué atrapar. Si trato de atrapar un const std::exception& y arrojas const char*, entonces no voy a atrapar tus cosas y podrían pasar cosas malas.

Realmente no importa qué tipo se tira y atrapa, siempre y cuando todos se apeguen a él. Supongo que std::exception se elige sobre const char* porque le permite poner más que solo una cadena en el objeto de excepción. Es simplemente más flexible.

2

Si hace que una regla en su código arroje excepciones solo derivadas de std :: exception, es más fácil capturarlas. En otras palabras, sólo puede tener una sola cláusula catch en std :: excepción:

catch (std::exception& e) 
{ 
    log_message(e); 
    throw; 
} 

Pero si usted no sigue esta regla, entonces al final tener que escribir cláusulas de captura cuando no tiene que hacerlo.

+0

hay poco beneficio para atrapar y volver a lanzar en cada capa, solo use una cláusula 'catch' si realmente tiene algo que hacer (y en C++, con RAII, esto debería ser lo suficientemente raro) o para" tragarlo ". –

+0

Me resulta útil para generar un seguimiento de pila para las excepciones que no se esperan. Ayuda a diagnosticar un error y hacer un seguimiento del origen de la excepción. – sashang

+0

Estoy de acuerdo en que las pilas son útiles, sin embargo, hay dos aspectos negativos en su enfoque. Primero desordena el código, ya no es obvio cuando se debe tomar una acción * específica * en caso de excepción. En segundo lugar, es un cerdo de alto rendimiento, porque la implementación de la excepción de costo cero que utilizan los compiladores populares, como gcc o Clang, impone una dura penalización a los lanzamientos. Hay otras alternativas, y las encuentro mejores. El código específico de plataforma para capturar la pila en el punto de lanzamiento es uno; otra es utilizar RAII para registrar "notas" que se agregan a la excepción durante el desenrollado. –

1

Un punto adicional provocada por otras respuestas es esto -

Si se lanza un entero o una cadena y que se desea capturar una error específico no se puede. Debe capturar todas las excepciones "int" y luego comparar las que desea capturar, y luego volver a lanzar las que no esté preparado para tratar. Si heredas de la excepción, puedes atrapar la excepción específica que deseas manejar y aún así tener la ventaja de poder capturar std :: exception si quieres manejarlas todas.

Cuestiones relacionadas