Pregunta

Me debatía con algunos colegas sobre lo que ocurre cuando se lanza una excepción en una asignación dinámica de clase.Sé que malloc se llama, y, a continuación, el constructor de la clase.El constructor nunca vuelve, entonces, ¿qué le sucede a la malloc?

Considere el siguiente ejemplo:

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

¿Qué sucede con la memoria malloced o, no se fuga?¿El CRT capturar la excepción del constructor y desasignar la memoria?

Saludos!
Rica

¿Fue útil?

Solución

Una llamada a

new B();

resuelve en dos cosas:

  • asignación con un operador nuevo () (ya sea el mundial uno o una específica clase, potencialmente una colocación uno con el new (xxx) B() sintaxis)
  • llamando al constructor.

Si la tirada de constructor, el operador correspondiente de eliminación se ha llamado. El caso en el que la eliminación correspondiente es una colocación es el único caso en que una colocación eliminar operador se llama sin la sintaxis :: operator delete (). delete x; o delete[] x; no llame a la colocación de borrar los operadores y no hay una sintaxis similar a la colocación de nuevo a llamarlos.

Tenga en cuenta que mientras que el destructor de B será no ser llamado, ya construidos subobjetos (miembros o B y la base de las clases B) será destruido antes de la llamada al operador de borrar. El constructor que no se llama es el de B.

Otros consejos

Cuando se produce una excepción desde el constructor, la memoria asignada por el nuevo es liberado, pero el destructor de la clase B no se llama.

En este caso, el objeto, o, en realidad no queda construida, y la memoria asignada por la nueva se libera. Como tal, el destructor no consigue llamado. Por lo que no necesita llamar a:

delete o;

Un patrón de diseño interesante es RAII - Raii. En este modelo, se utiliza un constructor para encapsular la adquisición de un recurso, y liberar el recurso en el destructor. Si el recurso no puede ser adquirido, se lanza en el constructor - al igual que su ejemplo. Por lo tanto, si usted tiene un objeto válido, tiene el recurso.

Si se construye el objeto, entonces usted ha adquirido con éxito el recurso. Esto significa que para la vida del objeto, es el propietario del recurso. Cuando se elimina el objeto, el recurso es liberado. Si el objeto no se construye, entonces nunca adquirió el recurso. Ver Wikipedia:

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

Desde el C ++ 2003 Standard 5.3.4 / 17 - Nuevo:

  

Si se puede encontrar cualquier parte de la inicialización objeto descrito anteriormente termina por lanzar una excepción y una función de cancelación de asignación adecuada, la función de cancelación de asignación se llama para liberar la memoria en la que se estaba construyendo el objeto, después de lo cual la excepción continúa propagándose en el contexto de la nueva expresión. Si ninguna función de cancelación de asignación inequívoca a juego se puede encontrar, propagando la excepción no causa la memoria del objeto a ser liberado. [Nota: Esto es apropiado cuando la llamada función de asignación no asigna memoria; de lo contrario, es probable que resulte en una pérdida de memoria. ]

Así que puede o no puede haber una fuga - que depende de si un deallocator adecuada se puede encontrar (que normalmente es el caso, a menos que el operador new / delete han sido invalidada) .En el caso en el que hay un deallocator adecuado, la compilador es responsable de cableado en una llamada a que si el constructor lanza.

Tenga en cuenta que esto es más o menos ajenos a lo que ocurre con los recursos adquiridos en el constructor, que es lo que mi primer intento de respuesta discutido -. Y es una cuestión que se discute en muchos FAQ, artículos y publicaciones

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top