Compartilhar via


Exceções: liberando objetos em exceções

Este artigo explica a necessidade e o método de liberação de objetos quando ocorre uma exceção. Os tópicos incluem:

Exceções geradas pela estrutura ou pelo aplicativo interrompem o fluxo normal do programa. Portanto, é muito importante acompanhar de perto os objetos para que você possa descartá-los corretamente caso uma exceção seja gerada.

Há dois métodos primários para fazer isso.

  • Manipule as exceções localmente usando as palavras-chave try e catch, então destrua todos os objetos com uma instrução.

  • Destrua qualquer objeto no bloco catch antes de gerar a exceção fora do bloco para tratamento adicional.

Essas duas abordagens são ilustradas abaixo como soluções para o seguinte exemplo 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;
}

Conforme escrito acima, myPerson não será excluído se uma exceção for gerada por SomeFunc. A execução vai diretamente para o próximo manipulador de exceção externa, ignorando a saída da função normal e o código que exclui o objeto. O ponteiro para o objeto sai do escopo quando a exceção deixa a função, e a memória ocupada pelo objeto nunca será recuperada enquanto o programa estiver em execução. Isso é uma perda de memória; ela seria detectada usando o diagnóstico de memória.

Como tratar a exceção localmente

O paradigma try/catch oferece um método de programação defensiva para evitar perdas de memória e garantir a destruição de seus objetos no caso de exceções. O exemplo mostrado anteriormente neste artigo pode ser reescrito da seguinte maneira:

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;
}

Este novo exemplo configura um manipulador de exceção para capturar a exceção e tratá-la localmente. Ele então sai da função normalmente e destrói o objeto. O aspecto importante deste exemplo é que um contexto para capturar a exceção é estabelecido com os blocos try/catch. Sem um quadro de exceção local, a função nunca saberia que uma exceção havia sido gerada e não teria a oportunidade de encerrar normalmente e destruir o objeto.

Como gerar exceções após destruir objetos

Outra maneira de lidar com exceções é passá-las para o próximo contexto externo de tratamento de exceções. Em seu bloco catch, você pode fazer alguma limpeza de seus objetos alocados localmente e então gerar a exceção para processamento adicional.

A função de geração pode ou não precisar desalocar objetos heap. Se a função sempre desalocar o objeto heap antes de retornar no caso normal, ela também deverá desalocar o objeto heap antes de gerar a exceção. Por outro lado, se a função normalmente não desalocar o objeto antes de retornar no caso normal, você deverá decidir caso a caso se o objeto heap deve ser desalocado.

O seguinte exemplo mostra como os objetos alocados localmente podem ser limpos:

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;
}

O mecanismo de exceção desaloca automaticamente objetos de quadro; o destruidor do objeto de quadro também é chamado.

Se você chamar funções que podem gerar exceções, poderá usar blocos try/catch para garantir que você capture as exceções e tenha a oportunidade de destruir todos os objetos criados. Em particular, lembre-se de que muitas funções MFC podem gerar exceções.

Para obter mais informações, confira Exceções: como capturar e excluir exceções.

Confira também

Tratamento de exceção