分配内存后构造函数中未捕获的异常

时间:2012-12-12 11:30:12

标签: c++ exception constructor shared-ptr

我已经阅读了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的析构函数会被调用吗? 如果你能指出一个涵盖这种情况的适当和可靠的资源,我将不胜感激。

1 个答案:

答案 0 :(得分:3)

假设您更改代码以便编译,将调用p2a(现在为p2b)的析构函数,因为它已成功默认构造。但是,它仍将保留NULL,因为您在C::C正文中重置它的尝试失败。

new B分配的内存将由堆栈展开过程自动清理。但是,pintpsomeclass 都会被泄露,因为您没有为这些成员使用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的主体展开时,它们都会被销毁
  • 如果psomeclasspint是智能指针,则会释放其动态分配的内存。他们不是,所以这是泄露。

通常,使用初始化列表和RAII是更好的方式。

作为参考,可以从这篇(非常古老的)文章开始:GOTW 66