2010-12-22 111 views
23

它只是发生在我身上我想知道如何在下面的情况下释放资源。如果派生类析构函数抛出一个异常,基类析构函数会发生什么

class Base { 
    Resource *r; 

public: 
    Base() { /* ... */ } 
    ~Base() { 
    delete r; 
    } 
}; 

class Derived : public Base { 
public: 
    Derived() { /* ... */ } 
    ~Derived() { 
    /* Suddenly something here throws! */ 
    } 
}; 

int main() { 
    try { 
    Derived d; 
    } catch(...) { 
    /* what happened with Base::r !? */ 
    } 
} 

如果派生类析构函数抛出基类析构函数会被调用吗?或者会有泄漏?

+6

从内存,如果析构函数抛出会发生什么标准的定义是如此令人难以置信的复杂,一般可怕,没有人永远,永远从析构函数抛出。我也很确定,所有的标准容器都假设析构函数不在行。基本上,虽然我认为在技术上,这是合法的和明确的,但事实是,没有人会这样做,并且有很好的理由,所以千万不要这样做。 – Puppy 2010-12-22 11:29:00

+1

您在那里的示例应该没有问题。 d正在以正常的方式超出范围。如果事情可能会变得糟糕,如果原因d被破坏,堆栈正在处理另一个异常的一部分。这就是导致关于从不投入析构函数的经验法则的可能性。 – 2010-12-22 11:36:09

回答

20

根据§15.2/ 2:

被部分构造或部分被毁将对所有其完全构造子对象执行析构函数的对象,也就是,对于其中的构造已经完成执行子对象而析构函数尚未开始执行。

因此应该调用基类析构函数。也就是说,就像我们知道这将清理基类:

#include <iostream> 

struct foo 
{ 
    ~foo() 
    { 
     std::cout << "clean" << std::endl; 
    } 
}; 

struct bar : foo 
{ 
    bar() 
    { // foo is initialized... 
     throw 0; // ...so its destructor is run 
    } 
}; 

int main() 
{ 
    try 
    { 
     bar b; 
    } 
    catch (...) 
    { 
     std::cerr << "caught" << std::endl; 
    } 
} 

并认为这将清理员:

#include <iostream> 

struct foo 
{ 
    ~foo() 
    { 
     std::cout << "clean" << std::endl; 
    } 
}; 

struct bar 
{ 
    ~bar() 
    { // f has been initialized... 
     throw 0; // ...so its destructor will run 
    } 

    foo f; 
}; 

int main() 
{ 
    try 
    { 
     bar b; 
    } 
    catch (...) 
    { 
     std::cerr << "caught" << std::endl; 
    } 
} 

这也将清理基类:

#include <iostream> 

struct foo 
{ 
    ~foo() 
    { 
     std::cout << "clean" << std::endl; 
    } 
}; 

struct bar : foo 
{ 
    ~bar() 
    { // foo has been initialized... 
     throw 0; // ...so its destructor will run 
    } 
}; 

int main() 
{ 
    try 
    { 
     bar b; 
    } 
    catch (...) 
    { 
     std::cerr << "caught" << std::endl; 
    } 
} 

这是我对报价的理解。

1

基本的析构函数会被调用。在有效的C++中,Meyers建议异常不应该留下析构函数。 捕获析构函数内的异常并处理它,吞下它或终止。

+0

您是否有理由声明您的理由? – GManNickG 2010-12-22 11:32:43

+1

你写“我不认为”。我确实认为。什么? OP的声誉得分很高,显然希望得到更清晰的答案。 – 2010-12-22 11:36:10

1

确实调用了基类析构函数。示例代码:

#include 
#include 

class Base { 
public: 
    Base() { /* ... */ } 
    ~Base() { 
    printf("Base\n"); 
    } 
}; 

class Derived : public Base { 
public: 
    Derived() { /* ... */ } 
    ~Derived() { 
    printf("Derived\n"); 
    throw 1; 
    } 
}; 

int main() { 
    try { 
    Derived d; 
    } catch(...) { 
    printf("CAUGHT!\n"); 
    } 
} 

此打印:

Derived 
Base 
CAUGHT! 
相关问题