我认为最佳答案是错误的,仍然会泄漏内存。
如果构造函数抛出异常(因为它从未完成初始化,可能有些成员从未达到其构造函数调用),则类成员的析构函数将不会被调用。
它们的析构函数仅在类的析构函数调用期间才会被调用。这是有意义的。
这个简单的程序证明了这一点。
#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
: a1(NULL),
a2(NULL)
{
printf("B constructor\n");
a1 = new A(3);
throw "fail";
a2 = new A(5);
}
catch ( ... ) {
printf("B Cleanup\n");
delete a2;
delete a1;
}
~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());
a1 = new_a1;
a2 = new_a2;
}
}
祝你好运,Tzvi。