派生类构造函数中的异常

ren*_*nan 1 c++ inheritance constructor destructor exception

我有一些问题来处理派生类中的构造函数异常.当派生类构造函数抛出错误时,父类已经分配了一些对象.是否会调用父类析构函数?

例:

class A
{
  A() { /* Allocate some stuff */ };

  virtual ~A() { /* Deallocate stuff */ };
};

class B : public A
{
  B() 
  { 
    /* Do some allocations */
    ...

    /* Something bad happened here */
    if (somethingBadHappened) 
    {
      /* Deallocate B Stuff */
      ...

      /* Throws the error */
      throw Error; /* Will A destructor be called? I know B destructor won't */
    };

  };

  ~B() { /* Deallocate B Stuff */ };
}
Run Code Online (Sandbox Code Playgroud)

我想知道做以下事情是否是一个好主意:

B()
{ 
  /* Do some allocations */
  ...

  /* Something bad happened here */
  if (somethingBadHappened) 
  {
    /* Deallocate B Stuff */
    this->~B();

    /* Throws the error */
    throw Error; /* Will A destructor be called? I know B destructor won't */
  };
};
Run Code Online (Sandbox Code Playgroud)

如果没有,最新情况是什么?

Cha*_*had 6

异常将导致堆栈展开到正确捕获异常的位置.这意味着在抛出异常之前在范围中创建的任何对象都将被破坏,包括本示例中的基类对象.

试试这个:

#include <iostream>

class A
{
public:
  A() { std::cout << "A::A()\n";}
  ~A() {std::cout << "A::~A()\n";}
};

class B : public A
{
public:
   B()
   {
      std::cout << "B::B()\n";
      throw 'c';
   }

   // note: a popular point of confusion -- 
   //   in this example, this object's destructor
   //   WILL NOT BE CALLED!
   ~B()
   {
      std::cout << "B::~B()\n";
   }
};


int main()
{
   try
   {
      B b;
   }

   catch(...)
   {
      std::cout << "Fin\n";
   }
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出应为:(注意B::~B()不要调用)

A::A()
B::B()
A::~A()
Fin
Run Code Online (Sandbox Code Playgroud)

只要您不尝试释放尚未分配的资源,就可以安全地手动调用析构函数.更好地包裹这些资源在某种类型的RAII容器(std::auto_ptr,boost::shared_ptr等),以避免调用析构函数的必要性.

Mooing Duck提供了一个非常好的例子,说明了在构造函数中抛出异常时堆栈展开的工作方式:

堆栈在构造函数异常期间展开