C++: excepción en construtor o destructor

Cuando un constructor de clase lanza una excepción, los destructores para todos los objetos locales (objetos que forman parte de la clase que se está construyendo) son llamados. Si uno de los destructores llamados lanza una excepción, el método terminate será ejecutado.

En general, no se debería lanzar una excepción durante la ejecución de un constructor sin hacer un catch de la misma y llevar a acabo una “limpieza” de los recursos utilizados por la clase. Una solución sencilla podría ser utilizar el constructor por defecto para crear los miembros “seguros” de la clase y después llamar a un método de inicialización para los “no seguros”, incluyendo el exception handling en éste.

Veamos un ejemplo sencillo. Supongamos que tenemos el siguiente código:

class Employee {
   ...
   Image * m_pImage;
   AudioClip * m_pAudio;
};

Employee(..., string image, string audio) : ..., m_pImage(NULL), m_pAudio(NULL)
{
   ...
   m_pImage = new Image(image);
   m_pAudio = new AudioClip(audio); // throw point
}

Si el código “new AudioClip(audio)” lanza una excepción, el flujo de control sale del constructor y se produce un memory leak. El destructor sólo sería llamado si el objeto hubiera sido completamente construido, pero no ha sido así.

Entonces, la manera correcta de implementar ese constructor sería:

Employee(..., string image, string audio) : ..., m_pImage(NULL), m_pAudio(NULL)
{
   ...
   try {
      m_pImage = new Image(image);
      m_pAudio = new AudioClip(audio);
   }
   catch(...)
   {
      delete m_pImage;
      delete m_pAudio;
      throw;
   }
}

De manera que, si se levanta una excepción, los recursos reservados son liberados y se vuelve a despachar la excepción para que notificar al objeto que intentaba construir esta clase.

Esta solución es buena, funciona bien, excepto en el caso de que tengamos punteros constantes como miembros de la clase:

class Employee {
   ...
   Image * const m_pImage;
   AudioClip * const m_pAudio;
};

Estos miembros deben ser incializados por el incializador de miembros propio de la clase, donde no podemos poner bloques try… catch.

En este caso, podríamos utilizar la clase auto_ptr<> (o similar) como wrapper para los punteros, de manera que se conviertan en objetos locales a nuestra clase:

class Employee {
   ...
   auto_ptr<image> m_pImage;
   auto_ptr<audioClip> m_pAudio;
};

Como ya se ha dicho, si ocurre una excepción durante la ejecución del constructor, se ejecutan los destructores de todos los miembros locales a la clase. Es decir, se llamaría al destructor de auto_ptr<>, el cual libera, de la manera adecuada, todos los recursos reservados.

[Fuente: http://progtutorials.tripod.com]

Compartir:
  • Facebook
  • Twitter
  • Google Bookmarks
  • BarraPunto
  • DZone
  • Meneame

Relacionados:

  1. Diferencia entre ClassNotFoundException y NoClassDefFoundError

Tags: , , ,

Leave a Reply

Get Adobe Flash playerPlugin by wpburn.com wordpress themes