1.6.1a Excepciones en la Librería Estándar
§1 Sinopsis
Ciertos elementos del lenguaje y algunas utilidades de la Librería Estándar ( 5) pueden lanzan excepciones para señalar condiciones de error. Los objetos lanzados pertenecen a algún miembro de una jerarquía de clases que tiene el siguiente diseño:
exception
logic_error
domain_error
invalid_argument
length_error
out_of_range
runtime_error
range_error
overflow_error
underflow_error
bad_alloc
bad_cast
bad_exception
bad_typeid
Como puede verse, todas ellas derivan de la superclase exception,
definida en la cabecera <stdexcept>, que tiene la siguiente interfaz:
class exception {
public:
exception () throw();
exception (const exception&) throw();
exception& operator= (const exception&) throw();
virtual ~exception () throw();
virtual const char* what () const throw();
};
Esta clase tiene cinco métodos públicos, ninguno de los cuales puede lanzar una excepción. El más interesante es what(), que generalmente devuelve una descripción textual del error causante de la excepción.
Un logic_error
señala una inconsistencia en la lógica interna del programa, o la violación de cierta precondición en la
parte del software cliente (una rutina de usuario). Por ejemplo, el
método substr de la clase estándar string, lanza una
excepción del tipo out_of_range si se interroga
una subcadena (substring) situado más allá del final de la cadena.
Interfaz:
class logic_error : public exception {
public:
explicit logic_error (const string& what_arg);
};
De esta clase derivan las siguientes:
class domain_error : public logic_error {
public:
explicit domain_error (const string& what_arg);
};
class invalid_argument : public logic_error {
public:
explicit invalid_argument (const string& what_arg);
};
class length_error : public logic_error {
public:
explicit length_error (const string& what_arg);
};
class out_of_range : public logic_error {
public:
explicit out_of_range (const string& what_arg);
};
Los
runtime_error son aquellos que no pueden ser fácilmente previstos por anticipado, y
generalmente se deben a causas externas al programa. Por ejemplo, la ocurrencia de un
overflow aritmético como consecuencia de procesar argumentos que son perfectamente legales para una función.
class runtime_error : public exception {
public:
explicit runtime_error (const string& what_arg);
};
De aquí derivan las siguientes:
class range_error : public runtime_error {
public:
explicit range_error (const string& what_arg);
};
class overflow_error : public runtime_error {
public:
explicit overflow_error (const string& what_arg);
};
class underflow_error : public runtime_error {
public:
explicit underflow_error (const string& what_arg);
};
La excepción
bad_alloc se lanza cuando se agota la memoria disponible en el montón
(
4.9.20d). También deriva públicamente de la clase exception.
La excepción bad_cast
es generada cuando fracasa un modelado dynamic_cast al ser aplicado a una referencia
( 4.9.9c).
Responde a la siguiente interfaz:
class bad_exception : public exception {
public:
bad_exception() throw();
bad_exception(const bad_exception&) throw();
bad_exception& operator=(const bad_exception&) throw();
virtual ~bad_exception() throw();
virtual const char* what() const throw();
};
Cuando desde una función se pretende lanzar una excepción no prevista (de un tipo no incluido en su especificador de excepciones 1.6.4), la excepción se convierte en el tipo bad_exception.
La excepción
bad_typeid es lanzada cuando se intenta aplicar el operador typeid
(
4.9.14) a una expresión nula.
class bad_typeid : public exception {
public:
bad_typeid() throw();
bad_typeid(const bad_typeid&) throw();
bad_typeid& operator=(const bad_typeid&) throw();
virtual ~bad_typeid() throw();
virtual const char* what() const throw();
};
Ver ejemplo de bad_typeid ( 4.9.14).
§2 Las sentencias en que se puedan recibir excepciones de librería [1], deben estar
inexcusablemente incluidas en un bloque try. En caso contrario,
de producirse un error, el programa terminará sin más ceremonial que un
mensaje: Abnormal program termination
.
Como puede verse en sus declaraciones, las clases logic_error, runtime_error y las que derivan de ellas, tienen un constructor explicit ( 4.11.2d1) que acepta la forma genérica:
explicit exception_class (const string& what_arg);
Aquí se puede incluir como argumento una cadena alfanumérica explicativa del
error, que será más tarde devuelta por el método what
.
La forma normal de usarlo es la siguiente:
try {
...
if ( condicion ) {
throw runtime_error("runtime num. xxxx");
}
}
catch (const exception& e) { // captura todas las excepciones de la jerarquía
cout << "Error: " << e.what();
}
§3 Por las razones señaladas al tratar de la captura de excepciones
( 1.6.2),
la captura discriminada de este tipo de excepciones requieren comenzar siempre por la clase más derivada.
Ejemplo sin discriminación del tipo de error producido:
try { // posible lanzamiento
...
}
catch (...) { // captura
...
}
Ejemplo con poca discriminación:
try {
...
}
catch (bad_alloc){...}
catch (bad_cast){...}
catch (bad_exception){...}
catch (bad_typeid){...}
catch (exception) {...}
...
Este otro proporciona más información:
try {
...
}
catch (logic_error) {...}
catch (runtime_error) {...}
catch (bad_alloc){...}
catch (bad_cast){...}
catch (bad_exception){...}
catch (bad_typeid){...}
...
Mejor este otro con la máxima discriminación:
try {
...
}
catch ( domain_error) {...}
catch ( invalid_argument) {...}
catch ( length_error) {...}
catch ( out_of_range) {...}
catch ( range_error) {...}
catch ( overflow_error) {...}
catch ( underflow_error) {...}
catch (bad_alloc){...}
catch (bad_cast){...}
catch (bad_exception){...}
catch (bad_typeid){...}
...
Ejemplos relacionados:
Capturar excepciones en jerarquía de clases ( 1.6.2)
[1] Virtualmente en cualquier sentencia. Para que un programa C++ esté correctamente diseñado, debe contar con un sistema de captura de excepciones aunque sea rudimentario. No obstante, el creador del lenguaje nos advierte [1a] que el sistema de excepciones C++ no se ha pensado para hacer cada función tolerante a fallos, sino subsistemas completos. Sin que sea necesario establecer un sistema de detección de excepciones en cada función.