Pergunta

Eu estava debatendo com alguns colegas sobre o que acontece quando você lançar uma exceção em uma classe alocada dinamicamente. Eu sei que malloc é chamado, e em seguida, o construtor da classe. O construtor nunca retorna, então o que acontece com o malloc?

Considere o seguinte exemplo:

class B
{
public:
    B()
    {
        cout << "B::B()" << endl;
        throw "B::exception";
    }

    ~B()
    {
        cout << "B::~B()" << endl;          
    }
};

void main()
{
    B *o = 0;
    try
    {
        o = new B;
    }
    catch(const char *)
    {
        cout << "ouch!" << endl;
    }
}

O que acontece com o o memória malloced, isso vazar? O CRT capturar a exceção do construtor e desalocar a memória?

Felicidades!
Rica

Foi útil?

Solução

Uma chamada para

new B();

resolve em duas coisas:

  • alocando com um operador new () (ou o global ou uma classe específica, potencialmente uma colocação com o new (xxx) B() sintaxe)
  • chamar o construtor.

Se a reposição construtor, o operador correspondente exclusão é chamado. O caso em que a exclusão correspondente é uma colocação é o único caso em que um operador delete colocação é chamado sem a sintaxe :: operator delete (). delete x; ou delete[] x; não chamar os operadores Eliminar posicionamento e não há nenhuma sintaxe semelhante à colocação de novo para chamá-los.

Note que, enquanto o destruidor de B não ser chamado, já construídos subobjetos (membros ou B e classes de base de B) serão destruídas antes da chamada para operador excluir. O construtor que não é chamado é o único para B.

Outras dicas

Quando uma exceção é lançada a partir do construtor, a memória alocada pelo novo é liberado, mas o destruidor de classe B não é chamado.

Neste caso, o objeto, o, na verdade não se construiu, e a memória alocada pelo novo é liberado. Como tal, o destruidor não obter chamado. Então você não precisa chamar:

delete o;

Um padrão de design interessante é RAII - Resource aquisição é inicialização. Neste padrão, você usa um construtor para encapsular a aquisição de um recurso, e liberar o recurso no processo de destruição. Se o recurso não pode ser adquirido, você joga no construtor - muito parecido com o seu exemplo. Assim, se você tem um objeto válido, você tem o recurso.

Se o objeto é construído, então você ter adquirido o recurso com sucesso. Isto significa que para a vida do objeto, que possui o recurso. Quando o objeto é excluído, o recurso é liberado. Se o objeto não é construído, então você nunca adquiriu o recurso. Veja wikipedia:

http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization

A partir do C ++ 2003 Standard 5.3.4 / 17 - Novo:

Se qualquer parte da inicialização do objecto descrito acima termina por gerar uma exceção e uma função desatribuição adequado pode ser encontrado, a função desatribuição é chamado para libertar a memória em que o objecto foi sendo construído, após o qual a excepção continua a propagar no contexto da nova-expressão. Se nenhuma função deallocation correspondência inequívoca pode ser encontrado, propagar a exceção não causa a memória do objeto a ser libertado. [Nota: Isto é apropriado quando a chamada função de alocação não aloca memória; caso contrário, é provável que resulte em uma fuga de memória. ]

Portanto, não pode ou não ser um vazamento - que depende se um desalocador apropriado pode ser encontrado (que é normalmente o caso, a menos que operator new / delete ter sido substituído) .No caso em que há uma desalocador adequado, o compilador é responsável por fiação em uma chamada para que se o construtor lança.

Note que este é mais ou menos alheios ao que acontece com recursos adquiridos no construtor, que é o que a minha primeira tentativa de uma resposta discutido -. E é uma questão que é discutida em muitos FAQs, artigos e postagens

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top