2011-09-27 21 views
8

que pueda hacer esto, no hay problema:qué try ... catch requiere tipo exacto arrojado

long lngval = 3L; 
int i = lngval; 

pero si intento esto:

try { 
    throw 3L; 
} 

catch(int i) { 
    cout << "caught " << i << endl; 
} 

me sale una excepción no controlada.

Esto parece inconsistente. ¿Cuál es el motivo de la no conversión de tipo en este caso?

+6

Escribe 100 veces: "Lanzaré solo objetos que deriven de std :: exception" –

+1

@Tadeusz Excepto con la expresión común de lanzar un 'int' para terminar un programa. ('main' contiene un' try ... catch' para capturar 'int' y devolverlo. Este modismo tiene el mismo efecto que llamar' exit', ** excepto ** que se llaman destructores de todas las variables locales.) –

+0

@JamesKanze: interesante, no sabía sobre este modismo. Vi una "SuicideException" que heredó de la nada, una vez, adivino el papel. En ambos casos, aunque realmente en el hecho de que nadie alguna vez escribió una cláusula 'catch (...)'. –

Respuesta

7

En el primer caso, la el compilador puede decir exactamente lo que quiere hacer: convertir un long en un int. En el segundo caso, el compilador tiene que asumir que es posible que tenga una construcción como esta:

try { 
    try { 
    throw 3L; 
    } 
    catch (int i) { /* P */ } 
} 
catch (long l) { /* Q */ } 

La idea es que el compilador no puede saber si puede haber un catch (long l) al acecho fuera del contexto actual, por lo que nunca es seguro para elegir la primera conversión posible.

Esta es la razón por la que es común el uso de una jerarquía de clases al lanzar excepciones en lugar de tipos al azar, como int o long: hace que sea fácil de añadir más o menos la especificación de sus controladores de excepciones de tal manera que el compilador puede ser seguro de sus intenciones (a través de la relación is-a).

0

Puede capturar varios tipos en un bloque try-catch. Para que el compilador sepa qué bloque catch lanzar, debe poder coincidir con el tipo exacto. O puede tener un bloque catch predeterminado: catch (...) {}, pero no podrá obtener el valor arrojado en ese caso.

1

La declaración de captura capta un objeto (o una variable escalar en sus casos) dado su tipo, por lo que si el tipo no coincide, pasa a la siguiente declaración de captura (si hay una) o al receptor de excepciones predeterminado.

En su caso, podría tener una segunda declaración de captura atrapada por mucho tiempo, y tal vez en otro lugar, por lo que su declaración de captura no captará nada.

para capturar cualquier excepción, sólo tiene que utilizar la captura() {} :)

Una sola punta, mejor clase de uso de excepción, o subclase para usted propia necesidad :)

1

También puede throw 3; - ningún problema.

int y long son tipos diferentes. Una ventaja del manejo de excepciones es que puedes distinguir las excepciones además de mirar su tipo (un bloque try central puede manejar excepciones de varios tipos/un bloque try puede manejar solo algunos tipos de excepciones, permitiendo que otros se propaguen).

Además, se recomienda lanzar una de las excepciones estándar o derivar una clase de una de ellas. Entonces podría simplemente catch (const std::exception&) si solo desea manejar la excepción y no le importa el tipo en particular.

4

catch hace no Necesitamos necesariamente el tipo exacto.

Es una práctica común y buena para usar excepciones derivadas de std::exception (se encuentra en <stdexcept>).La razón es que puede atrapar polimórficamente, es decir, si no necesita saber el tipo exacto (consulte también Difference: std::runtime_error vs std::exception()) y que tenemos una convención para manejar esto.

Cualquiera que utilice uno de los proporcionados por la norma (por ejemplo std::range_error), o si nada se adapte a sus problemas [suficientes], se especializan std::exception:

#include <stdexcept> 

class moores_law_stopped : public std::exception { 
public: 
    virtual ~moores_law_stopped() throw() {} 
    virtual const char *what() const throw() { 
     return "moores law stopped. duck under your table."; 
    } 
}; 



#include <iostream> 
int main() { 
    try { 
     throw moores_law_stopped(); 
    } catch (std::exception const &e) { 
     std::cerr << "oh oh: " << e.what() << std::endl; 
    } 
} 

Salida:

oh oh: moores law stopped. duck under your table. 

El La convención es capturar por referencia o referencia constante, para que pueda obtener un comportamiento polimórfico sin temor a object slicing.