Creo que la respuesta más común es equivocado y todavía perder memoria. Se llamará al destructor para los miembros de la clase no si el constructor lanza una excepción (porque nunca completó su inicialización, y tal vez algunos miembros nunca han llegado a sus llamadas al constructor). Sus destructores solo se invocan durante la llamada al destructor de la clase. Eso solo tiene sentido.
Este sencillo programa lo demuestra.
#include <stdio.h>
class A
{
int x;
public:
A(int x) : x(x) { printf("A constructor [%d]\n", x); }
~A() { printf("A destructor [%d]\n", x); }
};
class B
{
A a1;
A a2;
public:
B()
: a1(3),
a2(5)
{
printf("B constructor\n");
throw "failed";
}
~B() { printf("B destructor\n"); }
};
int main()
{
B b;
return 0;
}
Con la siguiente salida (usando g ++ 4.5.2):
A constructor [3]
A constructor [5]
B constructor
terminate called after throwing an instance of 'char const*'
Aborted
Si su constructor falla a la mitad, entonces es su responsabilidad para tratar con él. Peor aún, ¡la excepción puede ser lanzada desde el constructor de su clase base! La forma de tratar estos casos es empleando un "bloque de prueba de función" (pero incluso entonces debe codificar cuidadosamente la destrucción de su objeto parcialmente inicializado).
El enfoque correcto para su problema sería entonces algo como esto:
#include <stdio.h>
class A
{
int x;
public:
A(int x) : x(x) { printf("A constructor [%d]\n", x); }
~A() { printf("A destructor [%d]\n", x); }
};
class B
{
A * a1;
A * a2;
public:
B()
try // <--- Notice this change
: a1(NULL),
a2(NULL)
{
printf("B constructor\n");
a1 = new A(3);
throw "fail";
a2 = new A(5);
}
catch (...) { // <--- Notice this change
printf("B Cleanup\n");
delete a2; // It's ok if it's NULL.
delete a1; // It's ok if it's NULL.
}
~B() { printf("B destructor\n"); }
};
int main()
{
B b;
return 0;
}
Si lo ejecuta usted conseguirá el resultado esperado en el que sólo los objetos asignados se destruyen y se liberaron.
B constructor
A constructor [3]
B Cleanup
A destructor [3]
terminate called after throwing an instance of 'char const*'
Aborted
Aún puede trabajar con punteros inteligentes compartidos si lo desea, con copia adicional. Escribir un constructor similar a esto:
class C
{
std::shared_ptr<someclass> a1;
std::shared_ptr<someclass> a2;
public:
C()
{
std::shared_ptr<someclass> new_a1(new someclass());
std::shared_ptr<someclass> new_a2(new someclass());
// You will reach here only if both allocations succeeded. Exception will free them both since they were allocated as automatic variables on the stack.
a1 = new_a1;
a2 = new_a2;
}
}
Buena suerte, Tzvi.
Lo sé, tengo una naturaleza horrible, que no puedo resistir a nitpick. No puedo evitarlo Mis 2 centavos: declaración objsomeclass = someclass(); es innecesario En el cuerpo del constructor, objsomeclass ya está inicializado por defecto. objsomeclass (someclass()) a continuación tampoco tiene sentido. –
Estoy de acuerdo, pero creo que someclass tiene un constructor explícito. Y yo quería centrarme en el objeto creado en el constructor – yesraaj
Sí, sé que es solo un ejemplo. Es por eso que lo llamé quisquilloso. BTW constructor base() podría ser público :) –