FAQ Lite
Manejo de Exceções e Erros

[ 17.1 ] Como posso manejar um construtor que falha?
[ 17.2 ] Como eu posso manejar os recursos se o meu construtor aciona uma exceção?
[ 17.3 ] Como eu altero o string-length de uma matriz de char para prevenir perda de memória se/quando algo aciona uma exceção?

[ 17.1 ] Como posso manejar um construtor que falha?

Acionando uma exceção.

Construtores não têm qualquer tipo de informação de retorno, portanto não é possivel usar códigos de erro. A melhor maneira de sinalizar que um construtor falhou é acionar uma exceção.

Se você não tem, ou não quer usar tratamentos de exceção, aqui está uma maneira de contornar o problema. Se um construtor falha, o construtor ainda pode colocar o objeto em um estado de morte aparente. Ele faz isso ligando um bit de controle interno de estado, de tal modo que o objeto atua como se estivesse morto, ainda que esteja tecnicamente vivo. Adicione então uma função membro query (inspector) para verificar o estado desse bit de controle interno. Assim, seus usuários vão poder descobrir se o objeto está realmente vivo, ou está em estado de morte aparente. Provavelmente você vai querer também que suas outras funções membro verifiquem o bit indicador de morte aparente, e, se o objeto não estiver mais vivo, executem uma operação qualquer de tratamento da situação (algo melhor do que o abominável abort()). Essa solução é realmente feia, mas é o melhor que se pode ter quando não se quer, ou não se pode, usar o tratamento de exceções do compilador.

Topo
[ 17.2 ] Como eu posso manejar os recursos se o meu construtor aciona uma exceção?

Todos os dados membro dentro de seu objeto devem limpar sua própria sujeira.

Se um construtor aciona uma exceção, o destrutor do objeto não está em execução. Se seus objetos já fizeram qualquer coisa que precisa ser desfeita (como alocar memória, abrir um arquivo, travar um semáforo, etc) a "lista de coisas a desfazer" deve ser tratada por um dado membro dentro do objeto.

Por exemplo, ao invés de alocar memória em um dado membro Fred*, coloque a memória alocada em um objeto membro do tipo smart pointer, e o destrutor para esse smart pointer vai delete o objeto Fred quando o smart pointer morrer. A classe padrão auto_ptr é um exemplo del tal classe smart pointer. Você pode também escrever seu próprio smart pointer para contagem de referência. Você pode também usar smart pointer para apontar registros em disco ou objetos em outras máquinas.

Topo
[ 17.3 ] Como eu altero o string-length de uma matriz de char para previnir perda de memória se/quando algo aciona uma exceção?

Se o que você realmente quer é trabalhar com strings, não use uma matriz de char como primeira opção, já que matrizes são miseráveis. Ao invés disso use uma classe string qualquer.

Por exemplo, suponha que você recebe a cópia de um string, expande a cópia do string, e acrescenta outro string ao fim da cópia já expandida. A abordagem matriz de char se parecerá com algo assim:

void userCode(const char* s1, const char* s2)
    {
      // Get a copy of s1 into a new string called copy:
      char* copy = new char[strlen(s1) + 1];
      strcpy(copy, s1);
    
      // Now that we have a local pointer to freestore-allocated memory,
      // we need to use a try block to prevent memory leaks:
      try {
    
        // Now we fiddle with copy for a while...
        // ...
    
        // Later we want to append s2 onto the fiddled-with copy:
        // ... [Here's where people want to reallocate copy] ...
        char* copy2 = new char[strlen(copy) + strlen(s2) + 1];
        strcpy(copy2, copy);
        strcpy(copy2 + strlen(copy), s2);
        delete[] copy;
        copy = copy2;
    
        // Finally we fiddle with copy again...
        // ...
      } catch (...) {
        delete[] copy;   // Prevent memory leaks if we got an exception
        throw;           // Re-throw the current exception
      }
    
      delete[] copy;     // Prevent memory leaks if we did NOT get an exception
    } 
Usar char dessa maneira é tedioso e sujeito a erros. Porque não usar um objeto de alguma classe string? O seu compilador provavelmente fornece classes do tipo string, que certamente são mais velozes, muito mais simples e mais seguras  que o código char* que você mesmo escreve. Por exemplo, se você está usando uma classe string do Comitê de Padronização, seu código poderá se parecer com algo assim
#include <string>           // Let the compiler see class string
    using namespace std;
    
    void userCode(const string& s1, const string& s2)
    {
      // Get a copy of s1 into a new string called copy:
      string copy = s1;         // NOTE: we do NOT need a try block!
    
      // Now we fiddle with copy for a while...
      // ...
    
      // Later we want to append s2 onto the fiddled-with copy:
      copy += s2;               // NOTE: we do NOT need to reallocate memory!
    
      // Finally we fiddle with copy again...
      // ...
}      // NOTE: we do NOT need to delete[] anything! 
Topo Anterior Próximo Índice
C++ FAQ Lite
Copyright © 1991-98 by Marshall Cline Ph.D., cline@parashift.com
Tradução: Dagoberto Haele Arnaut

| Home | Bookmarks | Universidades | Para Saber mais | Universidades | WEB Directory | Mapa do site |