La descarga está en progreso. Por favor, espere

La descarga está en progreso. Por favor, espere

Desarrollador Profesional de Juegos Programación III Unidad I Capturar Excepciones.

Presentaciones similares


Presentación del tema: "Desarrollador Profesional de Juegos Programación III Unidad I Capturar Excepciones."— Transcripción de la presentación:

1 Desarrollador Profesional de Juegos Programación III Unidad I Capturar Excepciones

2 Capturar excepciones Recordemos que el manejador de excepciones ("handler") es un bloque de código precedido por la palabra catch. Este bloque debe seguir inmediatamente el bloque try o a otro bloque catch según el siguiente esquema: try { // bloque-intento... // posibles errores } catch (TipoA a) { // capturar errores A... } catch (TipoB b) { // capturar errores B... }... // código sigue acá La sintaxis es: catch ( [ ]) { } es el tipo de excepción que se capturará en esta sentencia. Ejemplo: try {... if (x > limite) throw "Overflow"; } catch (char* ) { cout << “¡error recibido ! "; }

3 Capturar excepciones Eventualmente se puede añadir un identificador, que puede ser usado en el cuerpo del bloque, de forma análoga a los argumentos de las funciones. struct E{ char* msg; };... try {... if (x > limite) { E e = { "Error desconocido" }; throw e; } } catch (E r) { cout << "Recibido: " << r.msg << endl; } Si el objeto capturado es recibido por valor o por referencia, el bloque catch puede escribirse de las siguientes maneras: Por valor catch(T t) {...} o catch(const T t) {...} Por referencia catch(T& t) {...} o catch(const T& t) {...} que es la más utilizada Su comportamiento y estructura es muy parecida al de una función. Aunque con diferencias, se puede pensar en él como una auténtica función. También aquí se establecen ciertas reglas de "congruencia de los argumentos“ para ver que bloque-catch va a responder a una excepción determinada

4 Concordancia Debe existir un manejador para cada excepción diferente que pueda el programa lanzar. El mismo, captura a una excepción cuando el tipo de esta coincide (según ciertas reglas ) con el tipo de. Al producirse la concordancia, el stack se descarga hasta la instrucción del "handler" al que se le transfiere el control. Entonces el manejador es el que decide como tratar adecuadamente a la anormalidad detectada. Ejemplo: try { // bloque-intento... // posibles errores aritmetic u overflow if (...) throw Aritmetic;... if (...) throw Overflow;... } catch (Aritmetic a) { // acá captura errores aritméticos... } catch (Overflow o) { // acá captura errores de overflow... }... // si no hay errores sigue por acá Si no existe un manejador adecuado para una excepción determinada, se desencadena un protocolo que, por defecto, produce inmediatamente la finalización del programa (ver excepciones imprevistas).

5 Reglas de concordancia Como vimos anteriormente, la excepción es capturada por el bloque-catch cuyo argumento coincida con el tipo de objeto lanzado por la sentencia throw. La búsqueda de coincidencia se realiza sucesivamente sobre los bloques catch en el orden en que aparecen en el código hasta que aparece la primera concordancia. Luego de ejecutarse este bloque, el programa sigue su ejecución después del último de los manejadores que sigan al bloque try que lanzó la excepción, sin que se realice una ulterior evaluación de otros posibles manejadores para la excepción lanzada. Por lo tanto, el orden de colocación de los bloques catch es determinante. Si se incluye un manejador universal, el mismo debería ser el último. La concordancia sigue ciertas reglas. El objeto e lanzado por la sentencia throw E() será capturado por un bloque catch(C c) si se cumple alguna de las siguientes condiciones: E y C son del mismo tipo. C es una super-clase de E visible en el punto de lanzamiento de la excepción. Por esta razón, cuando se captura una excepción y esta pertenece a una jerarquía de clases, hay que comenzar por capturar la clase más derivada. C y E son punteros a clases de una misma jerarquía, y existe una conversión estándar de E a C en el punto de lanzamiento de la excepción. La norma subyacente bajo las condiciones anteriores es que E y C deben coincidir exactamente, o la excepción E capturada, debe ser derivada del parámetro C del "catcher".

6 Explicación El siguiente ejemplo finaliza sin capturar a la excepción.... class A { }; class B { }; void foo() { throw A; } // se lanza un tipo A int main() { try { foo(); } catch( B ) { cout << "Capturada la excepción B" ; abort(); } En este ejemplo si es capturada... class Base {}; class Derivada : public Base { }; void foo() { throw Derivada( ); } Int main() { try { foo(); } catch(Base) { cout<<"Capturada la excepción Base"; }

7 El manejador universal También existe la posibilidad de definir un manejador que pueda capturar cualquier excepción. La sintaxis es la siguiente: catch (...) { } La sentencia catch captura cualquier excepción sin importar el tipo. Existe solamente un catch para el bloque try. Ejemplo: #include using namespace std; bool ok; class Out { }; void foo(bool pvez) { if (pvez) throw Out(); } void test() try { foo(true); } catch(...){ ok = true; } // puede capturar cualquier excepción } int main() { ok = false; test(); return ok ? (cout<<“Excepción capturada",0) : (cout<<“No hay excepción",1); } Salida Excepción capturada

8 Salto a una etiqueta Es posible también utilizar un sentencia goto para transferir el control del programa afuera de un manejador. Vemos el ejemplo visto en el modulo 2 modificado. #include bool ok; class Out { }; // Clase para instanciar el objeto a lanzar void foo(bool pvez); // prototipo de una funcion int main() { try { // bloque try ok = true; foo( true ); } catch( Out o) { // manejador que captura la excepción goto fallo; // salta a la etiqueta fallo } return (cout<<"Acierto!“, 0); fallo:// etiqueta return (cout<<"¡Fallo!“, 1); } void foo(bool pvez){ // definición de la function foo if( pvez ) throw Out(); // Lanza la excepción }

9 Las excepciones pueden ser anidadas a cualquier nivel (existir bloques try dentro de otros bloques try y bloques catch). Para mantener la regla que indica que un bloque try debe ser seguido inevitablemente por un catch, entonces pueden existir secuencias try-catch dentro de bloques try y de bloques catch. Excepciones anidadas Secuencias anidadas en el try. class Error { }; void foo () {... try { // Bloque-intento 1... try { // Bloque-intento en 1.1... } catch { // Handler de 1.1 captura excepciones de 1.1 }... // continúa bloque 1 } catch (Error) { //Handler de 1: captura excepciones de 1 }... // sigue a bloque 1 } Secuencias anidadas en el catch class Error { }; void foo () {... try { // Bloque-intento 1... } catch (Error) { // Handler de 1: captura excepciones de 1 try { // Bloque-intento en Handler-H1... } catch { // Handler de H1.1 captura excepc. de H1.1 }... // continúa handler H1 }... // sigue a bloque 1 }

10 Ejemplo 1: #include class Base{ }; class Derivada1: public Base{ }; class Derivada2: public Base{ }; void foo(int valor); int main() { try { foo(0); } catch(const Derivada1&) { cout<<"Estoy en Derivada 1"<<endl; } catch(const Derivada2&) { cout<<"Estoy en Derivada 2" <<endl; } try { foo(1); } catch(const Derivada1 &) { cout<<"Estoy en Derivada 1"<<endl; } catch(const Derivada2 &) { cout<<"Estoy en Derivada 2"<<endl; } return 0; } void foo(int valor) { if (valor==1) throw( Derivada1() ); else throw( Derivada2() ); } Salida Estoy en Derivada 2 Estoy en Derivada

11 Ejemplo 2: Vemos que cuando se captura una excepción y esta pertenece a una jerarquía de clases, se comienza por la clase más derivada, sino se pierde la capacidad de discriminar el tipo de excepción acontecido. class Base{ }; class Derivada1: public Base{ }; class Derivada2: public Base{ }; void foo( int valor) { switch(valor){ case 1 : throw( Derivada1() ); break; case 2 : throw( Derivada2() ); break; default : throw( Base() ); break; } int main() { try { foo(0); } // estas sentencias están en el orden adecuado catch(const Derivada1&) { cout<<"estoy en Derivada1"; } catch(const Derivada2&) { cout<<"estoy en Derivada2" ; } catch(const Base& ) { cout<<"estoy en Base" ; } try { foo(1); } catch(const Derivada1& ) { cout<<"estoy en Derivada1"; } catch(const Derivada2&) { cout<<"estoy en Derivada2"; } catch(const Base& ) { cout<<"estoy en Base" ; } try { foo(2); } catch(const Derivada1& ){ cout<<"Base de Derivada1"; } catch(const Derivada2&) { cout<<"Base de Derivada2" ; } catch(const Base& ) { cout<<"Base" ; }

12 … try { foo(1); } catch(const Base& ) { cout<<"estoy (en donde??)”; } catch(const Derivada1&) { cout<<"estoy en Derivada1"; } catch(const Derivada2&) { cout<<"estoy en Derivada2" ; } try { foo(2); } catch(const Base& ) { cout<<"estoy (en donde??"; } catch(const Derivada1& ) { cout<<"estoy en Derivada1"; } catch(const Derivada2&) { cout<<"estoy en Derivada2" ; } return 0; } Salida estoy en Base estoy en Derivada1 estoy en Derivada2 estoy (en donde??) estoy (en donde??) /* Si en cambio capturamos a la clase base primero entonces perdemos la posibilidad de testear a la sub-clase de la excepción que se lanzó realmente */

13 Para solucionar el diseño anterior podríamos capturar solamente las excepciones de la clase-base y usar polimorfismo para discriminar la excepción: #include using namespace std; class Base { public: virtual void cartel() { cout << " Estoy en Base" << endl; } }; class Derivada1 : public Base { public: void cartel () { cout << "Estoy en Derivada1" << endl; } }; class Derivada2: public Base { public: void cartel () { cout << "Estoy en Derivada2" << endl; } }; void foo(int valor) { switch(valor){ case 1 : throw( Derivada1() ); break; case 2 : throw( Derivada2() ); break; default : throw( Base() ); break; } // continua

14 int main() { try { foo(0); } catch(Base& f) { f.cartel(); } try { foo(1); } catch(Base& f) { f.cartel(); } try { foo(2); } catch(Base& f) { f.cartel(); } return 0; } Salida Base Estoy en Derivada1 Estoy en Derivada2


Descargar ppt "Desarrollador Profesional de Juegos Programación III Unidad I Capturar Excepciones."

Presentaciones similares


Anuncios Google