Bloque try
Asocia uno o más controladores de excepciones (cláusulas catch
) con una instrucción compuesta.
Contenido |
[editar]Sintaxis
try instrucción-compuestasec-de-controladores | |||||||||
donde la sec-de-controladores es una secuencia de uno o más controladores que tiene la sintaxis siguiente:
catch ( atrib (opcional)sec-especificadores-de-tipodeclarador) instrucción-compuesta | (1) | ||||||||
catch ( atrib (opcional)sec-especificadores-de-tipodeclarador-abstracto (opcional)) instrucción-compuesta | (2) | ||||||||
catch ( ... ) instrucción-compuesta | (3) | ||||||||
instrucción-compuesta | - | secuencia de instrucciones encerrada entre llaves |
atrib(desde C++11) | - | lista opcional de atributos, se aplica al parámetro formal |
sec-especificadores-de-tipo | - | parte de una declaración de parámetro formal, lo mismo que en una lista de parámetros de función |
declarador | - | parte de una declaración de parámetro formal, lo mismo que en una lista de parámetros de función |
declarador-abstracto | - | parte de un declaración de parámetro formal sin denominación, lo mismo que en una lista de parámetros de función |
catch
que declara un parámetro formal denominado try{/* */}catch(conststd::exception& e){/* */}
catch
que declara un parámetro sin denominación try{/* */}catch(conststd::exception&){/* */}
catch
general, que se activa para cualquier excepción try{/* */}catch(...){/* */}
[editar]Explicación
- Véase lanzamiento de excepciones para mayor información sobre expresiones de lanzamiento.
Un bloque try
es una instrucción, y como tal, puede aparecer en cualquier lugar donde pueda aparecer una instrucción (es decir, como una de las intrucciones en una instrucción compuesta, incluida la instrucción compuesta del cuerpo de la función). Véase bloque try de función para los bloques try
alrededor de los cuerpos de funciones. La siguiente descripción se aplica tanto a los bloques try
como a los bloques try de función.
El parámetro formal de la cláusula catch
(sec-especificadores-de-tipo y declarador o sec-especificadores-de-tipo y declarador-abstracto) determina qué tipos de excepciones hacen que se ingrese a esta cláusula catch
. No puede ser un tipo de referencia rvalue,(desde C++11) un tipo clase abstracta, un tipo incompleto, o puntero a tipo incompleto (excepto que punteros a void (que pueden estar calificados-cv) están permitidos). Si el tipo del parámetro formal es tipo de array o tipo de función, se trata como el tipo puntero correspondiente (similar a una declaración de función).
Cuando se lanza una excepción por cualquier instrucción en instrucción-compuesta, el objeto excepción de tipo E
se compara con los tipos de los parámetros formales T
de cada cláusula catch en sec-de-controladores, en el orden en que se enumeran las cláusulas catch
. La excepción es una coincidencia si se cumple alguna de las siguientes condiciones:
E
yT
son del mismo tipo (ignorando los calificadores-cv de nivel superior enT
);T
es una referencia lvalue (que puede estar calificada-cv) aE
;T
es una clase base pública inequívoca deE
;T
es una referencia a una clase base pública inequívoca deE
;T
es (puede estar calificado-cv)U
oconst U &
(desde C++14), yU
es un puntero o puntero a tipo miembro, yE
también es un tipo de puntero o puntero a tipo miembro que es implícitamente convertible aU
por uno o más de:
- * una conversión de puntero estándar que no sea a una clase base privada, protegida o ambigua;
- * una conversión de calificación;
(desde C++17) |
T
es un puntero o un puntero a miembro o una referencia a un puntero constante(desde C++14), mientras queE
es std::nullptr_t.
try{ f();}catch(conststd::overflow_error& e){// esto se ejecuta si f() lanza std::overflow_error (regla de mismo tipo)}catch(conststd::runtime_error& e){// esto se ejecuta si f() lanza std::underflow_error (regla de clase base)}catch(conststd::exception& e){// esto se ejecuta si f() lanza std::logic_error (regla de clase base)}catch(...){// esto se ejecuta si f() lanza std::string o int o cualquier otro tipo no relacionado}
La cláusula general catch(...) coincide con las excepciones de cualquier tipo. Si está presente, debe ser la última cláusula catch
en la sec-de-controladores. El bloque catch
general se puede usar para garantizar que ninguna excepción no capturada pueda escapar de una función que ofrece la garantía de excepción de no lanzamiento.
Si no se encuentran coincidencias después de examinar todas las cláusulas catch
, la propagación de excepción continúa hasta el bloque try
que lo contiene, como se describe en la expresión de lanzamiento. Si no quedan bloques try
que los contenga, se ejecuta std::terminate (en este caso, se define por la implementación si se produce algún desenredo de la pila: se permite lanzar una excepción no atrapada para terminar el programa sin invocar ningún destructor).
Al ingresar a una cláusula catch
, si su parámetro formal es una clase base del tipo de excepción, es inicializada mediante la inicialización de copia desde el subobjeto de la clase base del objeto de excepción. De lo contrario, se inicializa por medio de la inicialización de copia desde el objeto de excepción (esta copia está sujeta a la elisión de copia).
try{std::string("abc").substr(10);// lanza std::length_error}// catch (std::exception e) // inicialización de copia desde la base std::exception// {// std::cout << e.what(); // información sobre length_error se perdió// }catch(conststd::exception& e)// referencia a base de un objeto polimorfo{std::cout<< e.what();// información de length_error se imprime}
Si el parámetro de la cláusula catch
es un tipo referencia, cualquier cambio realizado en él se refleja en el objeto de excepción, y puede observarse por otro controlador si la excepción se vuelve a lanzar con throw;. Si el parámetro no es una referencia, cualquier cambio realizado en él es local y su duración termina cuando el controlador termina.
Dentro de una cláusula catch , std::current_exception puede usarse para capturar la excepción en un std::exception_ptr, y std::throw_with_nested puede ser usada para construir excepciones anidadas. | (desde C++11) |
No se usará un instrucción goto o switch para transferir el control a un bloque try o a un controlador.
Aparte de lanzar o volver a lanzar la excepción, la cláusula catch
después de un bloque try
normal (no un bloque try de función) puede salir con una instrucción return, continue, break, goto, o llegar al final de su instrucción-compuesta. En cualquier caso, esto destruye el objeto de excepción (a menos que exista una instancia de std::exception_ptr que se refiera a él).
[editar]Notas
No se garantiza que la expresión de lanzamiento throwNULL; coincida con una cláusula catch
de puntero, porque el tipo de objeto de excepción puede ser int, pero throw nullptr; seguramente se corresponde con cualquier cláusula catch
de puntero o de puntero a miembro.
Si se coloca una cláusula catch
para una clase derivada después de la cláusula catch
para una clase base, la cláusula catch
de la derivada nunca se ejecutará.
try{ f();}catch(conststd::exception& e){// se ejecutará si f() lanza std::runtime_error}catch(conststd::runtime_error& e){// ¡código muerto!}
Si se utiliza goto para salir de un bloque try
y si alguno de los destructores de variables automáticas con ámbito de bloque que se ejecutan por la instrucción goto
arroja excepciones, esas excepciones se atrapan por los bloques try
en los que se definen las variables:
label:try{ T1 t1;try{ T2 t2;if(condition)goto label;// destruye a t2, luego destruye a t1, luego salta a la etiqueta}catch(...){}// atrapa la excepción del destructor de t2}catch(...){}// atrapa la excepción del destructor de t1
[editar]Palabras clave
[editar]Ejemplo
El siguiente ejemplo demuestra varios usos del bloque try
#include <iostream>#include <vector> int main(){try{std::cout<<"Lanzando una excepción de un entero...\n";throw42;}catch(int i){std::cout<<" la excepción del entero se atrapo, con valor: "<< i <<'\n';} try{std::cout<<"Creando un vector con 5 elementos... \n";std::vector<int> v(5);std::cout<<"Accediendo al onceavo elemento del vector...\n";std::cout<< v.at(10);// vector::at() lanza std::out_of_range}catch(conststd::exception& e)// atrapado por referencia a la base{std::cout<<" se atrapo una excepción estándar, con mensaje '"<< e.what()<<"'\n";} }
Posible salida:
Lanzando una excepción de un entero... la excepción del entero se atrapo, con valor: 42 Creando un vector con 5 elementos... Accediendo al onceavo elemento del vector... se atrapo una excepción estándar, con mensaje 'out_of_range'
[editar]Defect reports
Los siguientes informes de defectos de cambio de comportamiento se aplicaron de manera retroactiva a los estándares de C++ publicados anteriormente.
ID | Aplicado a | Comportamiento según lo publicado | Comportamiento correcto |
---|---|---|---|
CWG 98 | C++98 | una instrucción switch podía transferir el control a un bloque try o aun controlador | prohibido |
CWG 210 | C++98 | la expresión throw se comparaba con las cláusulas catch | el objecto excepción se compara con las cláusulas catch |
CWG 1166 | C++98 | no se especificó el comportamiento cuando coincide una cláusula catch cuyo tipo de excepción en una referencia a un tipo de clase abstracta | no se permiten los tipos de clase abstracta para las cláusulas catch |
CWG 1769 | C++98 | cuando el tipo de excepción declarado en la cláusula catch es una base del tipo del objeto de excepción, se podría usar un constructor de conversión para la inicialización del parámetro de la cláusula catch | el parámetro se inicializa mediante copia desde el subobjeto de clase base correspondiente del objeto de excepción |
CWG 2093 | C++98 | un objeto excepción de puntero a tipo objeto no podía coincidir con un controlador de puntero a tipo objeto mediante la conversión de calficación | permitido |