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.5  Excepciones en la práctica

§1  Sinopsis

Como se ha señalado anteriormente, en nuestras aplicaciones podemos prever la utilización de excepciones que lancen cualquier tipo de objeto. Por ejemplo, un int:

int exception1 = 1;

int exception2 = 2;

...

try {

   ...

   if ( /* cond-1 */ ) throw exception1;

   if ( /* cond-2 */ ) throw exception2;

   ...

}

catch (int e) {

   if (e = 1) { /* action 1 */ }

   else if (e = 2) { /* action 2 */ }

}


Sin embargo, salvo aplicaciones muy básicas, casi diríamos de experimentación, en la práctica estaremos usando librerías que a su vez lancen excepciones. De modo, que lo mejor es utilizar objetos de una clase definida por nosotros que derive de la excepción estándar, de la que a su vez podemos derivar tantas clases como aconsejen las circunstancias. De esta forma, podemos utilizar las mismas rutinas de captura para manejar nuestras excepciones y las que sean provocadas por las librerías.

Por ejemplo, supongamos que estamos programando las rutinas de comunicaciones de una aplicación Windows en la que empleamos las librerías Winsock, muchas de cuyas funciones lanzan excepciones en caso de error o circunstancias anómalas -por cierto muy frecuentes en las comunicaciones TCP/IP-. En este caso, para nuestras rutinas de comunicación podríamos utilizar una clase con el siguiente diseño:

class TCPexception : public std::exception {
   std::string message;
   public:
   TCPexception () :

                 message("Error en conexion TCP/IP") {}
   TCPexception (const std::string& str) :

                 message("Error en conexion TCP/IP:\n" + str) {} 

   virtual const char* what() const throw() {
      return message.c_str();
   }
};


Como puede verse, la clase incluye un constructor explícito sin argumentos que construye un mensaje estándar y otro con un parámetro que permite añadir una aclaración adicional según el caso.  Observe que el método what() que nos permitirá interrogar el mensaje del objeto capturado, goza de las siguientes características:

  • Es virtual -> pueden existir otras definiciones en clases derivadas
  • Devuelve un puntero a cadena de caracteres constante.
  • No puede lanzar excepciones
  • No puede modificar ninguna propiedad en la clase.


Con este diseño, podemos lanzar excepciones cuando las circunstancias lo exijan. Por ejemplo:

if ( /* condition-1 */ )

   throw TCPexception();

else if ( /* condition-2 */ )

   throw TCPexception("Connection closed by remote peer");


En estas circunstancias, nuestras operaciones de comunicación podrían estar controladas de la siguiente forma [1]:

try {

   /* rutinas de comunicacion */

}

catch (std::exception& e) {  // capturador-1
   std::cerr << e.what();
}
catch(...) {                 // capturador genérico
   std::cerr << "Unhandled exception";
}


Según se indicó al tratar de las reglas de concordancia para la captura de excepciones ( 1.6.2), un diseño como el presentado tiene la ventaja de que el capturador-1 permitirá la captura de nuestras excepciones junto con las posibles excepciones estándar que pudieran ser lanzadas por las librerías utilizadas -si están bien diseñadas, probablemente sus excepciones sean también derivadas de las excepciones estándar-, mientras que el capturador genérico que sigue, permitiría capturar todas las demás.

Respecto a la discriminación entre nuestras ecepciones y las que pudieran ser lanzadas por la librería, no existirá ningún problema al respecto según quedó demostrado en el ejemplo-3 de la página anterior  ( 1.6.2).

  Inicio.


[1]  Recordemos que en opinión del Dr. Stroustrup, el mecanismo C++ de excepciones no está pensado para controlar anomalías en funciones individuales sino en subsistemas completos.