Disponible la nueva versión "donationware" 7.3 de OrganiZATOR
Descubre un nuevo concepto en el manejo de la información.
La mejor ayuda para sobrevivir en la moderna jungla de datos la tienes aquí.

Curso C++

[Home]  [Inicio]  [Índice]


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)

  Inicio.


[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.

[1a]    Stroustrup & Ellis:  ACRM  §15.1.