如果派生类析构函数抛出异常,基类析构函数会发生什么

时间:2010-12-22 11:08:41

标签: c++ exception destructor memory-leaks

我刚好想到了以下情况下如何释放资源。

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 !? */
  }
}

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

3 个答案:

答案 0 :(得分: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 :(得分:1)

将调用基础析构函数。

在Effective C ++中,Meyers建议异常不应该留下析构函数。 在析构函数中捕获异常并处理它,吞下它或终止它。

答案 2 :(得分: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!