2011-10-10 15 views
5

El siguiente ejemplo deja una posible pérdida de memoria porque el destructor no se ejecuta para el objeto en el que se ejecuta la excepción durante la ejecución de su constructor. ¿Dónde manejo esta fuga de memoria?Captura de excepciones en el constructor

#include <exception> 

class MyClass { 

public: 
     MyClass() 
     { 
      c = new char[5]; 
      throw std::runtime_error("test"); 
     } 

     ~MyClass() 
     { 
      delete[] c; 
     } 

private: 
    char *c; 
}; 

int main() 
{ 
    try 
    { 
     MyClass Obj; 

    } 
    catch (std::runtime_error) 
    { 

    } 
} 

Respuesta

5

Usted es mejor usar RAII, puntero inteligente en este caso, para ser específicos.

O, como alternativa, puede usar Two Phased Construction estrategia.

Se puede usar siempre que encierra try-catch bloques dentro de cuerpo del constructor y explícitamente llamar a eliminar a todos aquellos recursos que se asigna dinámicamente pensar en el escenario en el que tiene n cantidad de recursos que se asigna de forma dinámica, se hace muy complicado de mantener de forma explícita pista de cada recurso que necesita desasignar en el catch, en tal escenario, RAII le proporciona la mejor solución porque entonces cada recurso se ocupa implícitamente de su propia desasignación y no necesita tener la sobrecarga de hacer un seguimiento de cada recurso.

boost::scoped_ptr o std::tr1::scoped_ptr son aptos para este escenario en lugar de cualquier puntero sin formato.

+2

¿Qué necesita para este voto a favor? RAII es la mejor manera de hacerlo, y si alguien dice lo contrario, es incorrecto. Si se siente responsable de rechazar votos, ¿se siente lo suficientemente responsable como para explicarnos por qué? Y si no puedes y solo * sientes * que esto está mal, entonces no estás lo suficientemente calificado para vencer, deja que alguien más haga eso. –

+0

es esta solución basada en cosas relacionadas con C++ 11? – user103214

+0

No, esto es C++ 03. –

6

Captura la excepción en el constructor, ordena (desasigna la memoria) y luego lanza la excepción sin la pérdida de memoria.

+0

Nunca se ha llamado al destructor cuando vuelvo a lanzar la excepción sin pérdida de memoria en el constructor. ¿Hay alguna razón para esto? – user103214

+1

@ user974191: la construcción del objeto no está completa hasta la llave final del constructor. Destructor solo se llama para Objeto que está completo. Si el constructor no se ejecutó por completo, el objeto no existe y, por lo tanto, no se invocará ningún destructor. –

1

se puede coger la excepción en el cuerpo del constructor, lo que hace la limpieza que necesita, a continuación, volver a lanzar la excepción con throw;

Dicho esto, las excepciones y la manipulación manual de la memoria no van muy bien juntos. Será mucho mejor utilizar un objeto que gestione automáticamente la memoria para el miembro c (por ejemplo, std::string, std::vector<char>, std::unique_ptr<char[]>, etc.). En realidad, solo necesita administrar la memoria explícitamente si está escribiendo una clase como una de las anteriores, cuyo propósito es exactamente cuidar esa memoria.

4

Una forma es throw la excepción condicional al principio del constructor y luego asignar la memoria.

MyClass() 
    { 
    if(<condition>) 
     throw std::runtime_error("test"); 
    c = new char[<SIZE>]; 
    } 

Otra forma es utilizar una sintaxis especial try-catch() que encierra el constructor:

MyClass() 
    try { 
    c = new char[5]; 
    throw std::runtime_error("test");; 
    } 
    catch(std::runtime_error e) { 
    delete[] c; 
    } 

Demo.

Cuestiones relacionadas