Excepciones: Liberar objetos en las excepciones

En este artículo se explica la necesidad y el método de liberar objetos cuando se produce una excepción. Contenido de los temas:

Las excepciones producidas por el marco o por la aplicación interrumpen el flujo de programa normal. Por lo tanto, es muy importante realizar un seguimiento cercano de los objetos para que puedas eliminarlos correctamente en caso de que se produzca una excepción.

Hay dos métodos principales para hacerlo.

  • Controla las excepciones localmente mediante las palabras clave try y catch, y, a continuación, destruya todos los objetos con una instrucción.

  • Destruye cualquier objeto del catch bloque antes de iniciar la excepción fuera del bloque para su posterior control.

Estos dos enfoques se muestran a continuación como soluciones para el siguiente ejemplo problemático:

void SomeFunc()        // Problematic code
{
   CPerson* myPerson = new CPerson;

   // Do something that might throw an exception.
   myPerson->SomeFunc();

   // Now destroy the object before exiting.
   // If SomeFunc above throws an exception this code will
   // not be reached and myPerson will not be deleted.
   delete myPerson;
}

Como se ha escrito anteriormente, myPerson no se eliminará si se produce una excepción por SomeFunc. La ejecución salta directamente al siguiente controlador de excepciones externo, omitiendo la salida de la función normal y el código que elimina el objeto. El puntero al objeto sale del ámbito cuando la excepción deja la función y la memoria ocupada por el objeto nunca se recuperará siempre que se ejecute el programa. Se trata de una fuga de memoria; se detectaría mediante el diagnóstico de memoria.

Controlar la excepción localmente

El paradigma try/catch proporciona un método de programación defensiva para evitar pérdidas de memoria y asegurarse de que los objetos se destruyen cuando se producen excepciones. Por ejemplo, el supuesto mostrado anteriormente en este artículo podría volver a escribirse de la siguiente manera:

void SomeFunc()
{
   CPerson* myPerson = new CPerson;

   try
   {
      // Do something that might throw an exception.
      myPerson->SomeFunc();
   }
   catch (CException* e)
   {
      // Handle the exception locally
      e->Delete();
   }

   // Now destroy the object before exiting.
   delete myPerson;
}

En este nuevo ejemplo se configura un controlador de excepciones para detectar la excepción y controlarla localmente. A continuación, sale de la función normalmente y destruye el objeto. El aspecto importante de este ejemplo es que se establece un contexto para detectar la excepción con los bloques try/catch. Sin un marco de excepción local, la función nunca sabría que se había producido una excepción y no tendría la oportunidad de salir normalmente y destruir el objeto.

Iniciar excepciones después de destruir objetos

Otra manera de controlar las excepciones es pasarlas al siguiente contexto externo de control de excepciones. En tu catch bloque, puedes realizar alguna limpieza de los objetos asignados localmente y, a continuación, iniciar la excepción para su posterior procesamiento.

La función excepción puede o no necesitar desasignar objetos de montón. Si la función siempre desasigna el objeto del montón antes de devolverlo en el caso normal, la función también debe desasignar el objeto del montón antes de iniciar la excepción. Por otro lado, si la función no suele desasignar el objeto antes de devolverlo en el caso normal, debes decidir mayúsculas y minúsculas si se debe desasignar el objeto del montón.

En el ejemplo siguiente se muestra cómo se pueden limpiar los objetos asignados localmente:

void SomeFunc()
{
   CPerson* myPerson = new CPerson;

   try
   {
      // Do something that might throw an exception.
      myPerson->SomeFunc();
   }
   catch (CException* e)
   {
      e->ReportError();
      // Destroy the object before passing exception on.
      delete myPerson;
      // Throw the exception to the next handler.
      throw;
   }

   // On normal exits, destroy the object.
   delete myPerson;
}

El mecanismo de excepción desasigna automáticamente los objetos de marco; también se llama al destructor del objeto marco.

Si llama a funciones que pueden producir excepciones, puede usar bloques try/catch para asegurarse de detectar las excepciones y tener la oportunidad de destruir cualquier objeto que haya creado. En concreto, tenga en cuenta que muchas funciones de MFC pueden producir excepciones.

Para más información, consulte Excepciones: Detección y eliminación de excepciones.

Consulte también

Control de excepciones