Я считаю, что верхний ответ неверен и все равно будет утечка памяти.
Деструктор для членов класса будет не вызываться, если конструктор выдает исключение (потому что он никогда не завершал свою инициализацию и, возможно, некоторые члены никогда не достигали своих вызовов конструктора).
Их деструкторы вызываются только во время вызова деструктора класса. Это имеет смысл только.
Эта простая программа демонстрирует это.
#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;
}
Со следующим выводом (используя g ++ 4.5.2):
A constructor [3]
A constructor [5]
B constructor
terminate called after throwing an instance of 'char const*'
Aborted
Если ваш конструктор потерпел неудачу на полпути, то вы несете ответственность за его устранение. Хуже того, исключение может быть сгенерировано из конструктора вашего базового класса!
Чтобы справиться с этими случаями, нужно использовать «блок попытки выполнения функции» (но даже тогда вы должны тщательно кодировать уничтожение частично инициализированного объекта).
Тогда правильный подход к вашей проблеме будет примерно таким:
#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;
}
Если вы запустите его, вы получите ожидаемый результат, в котором уничтожены и освобождены только выделенные объекты.
B constructor
A constructor [3]
B Cleanup
A destructor [3]
terminate called after throwing an instance of 'char const*'
Aborted
Вы можете по-прежнему работать с интеллектуальными общими указателями, если хотите, с дополнительным копированием. Написание конструктора, похожего на это:
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;
}
}
Удачи,
Цви.