我已经阅读了Michael Burr关于抛出异常的构造函数的精彩摘要,在这里:Will the below code cause memory leak in c++
我的问题是:当从构造函数调用的函数抛出异常时,行为是否相似?即,如果异常没有被捕获,它会被抛出,因此它会爬到构造函数并进一步调用到构造函数的函数。
我特别想知道该对象类中包含的成员对象,它们的析构函数是否会被调用?更具体地说,在我的例子中,它是关于boost :: shared_ptr类型的成员。
考虑以下示例:
class A {
A() { throw some_exception }
};
class B {
B() { A a = new A(); }
};
class C {
boost::shared_ptr<B> p2b;
int i;
int *pint;
someclass objsomeclass;
someclass* psomeclass;
public:
C() {
objsomeclass = someclass();
psomeclass = new someclass();
pint = new int();
p2b(new B);
}
};
void foo()
{
C c();
}
main()
{
foo();
}
p2a的析构函数会被调用吗? 如果你能指出一个涵盖这种情况的适当和可靠的资源,我将不胜感激。
答案 0 :(得分:3)
假设您更改代码以便编译,将调用p2a
(现在为p2b
)的析构函数,因为它已成功默认构造。但是,它仍将保留NULL,因为您在C::C
正文中重置它的尝试失败。
由new B
分配的内存将由堆栈展开过程自动清理。但是,pint
和psomeclass
都会被泄露,因为您没有为这些成员使用RAII。
为了澄清,让我们逐步完成代码:
C::C() {
objsomeclass = someclass();
psomeclass = new someclass();
pint = new int();
p2b.reset(new B);
/* in your code as posted, the call sequence is:
new B (allocate sizeof B)
-> B::B
-> new A (allocate sizeof A)
-> A::A which throws
<- new A failed, so memory is freed
<- B::B failed (initialized subobjects would be
destroyed here, but there are none)
new B failed, so memory is freed
*/
}
请注意:
C::C
的主体展开时,它们都会被销毁psomeclass
和pint
是智能指针,则会释放其动态分配的内存。他们不是,所以这是泄露。通常,使用初始化列表和RAII是更好的方式。
作为参考,可以从这篇(非常古老的)文章开始:GOTW 66