try块会保护局部变量的破坏吗?

时间:2015-12-14 22:36:34

标签: c++ exception

class A
  {
  public:
    ~A();
  };
A::~A()
  {
  std::cout<<"Destructor!!!\n"<<std::endl;
  std::exception e;
  throw e;
  }
void main()
  {
  try
    {
    A a;
    //A a1,a2;//This gives out two lines of "Destructor!!!" then the program terminates            
    }
  catch(std::exception)
    {
    std::cout<<"Caught!!!\n"<<std::endl;
    }
  }

我知道在析构函数中发出异常是一种不好的做法。但它不违法。 上面的程序进入catch块。似乎try块正在防止局部变量的破坏。 但是,如果我取消注释代码,它会给出不同的东西。在这种情况下,似乎没有处理第一个异常,并且终止是由多个异常引起的。 现在我不确定在激励功能时是否会破坏局部变量。我使用的是VS2005 btw。

1 个答案:

答案 0 :(得分:3)

try / catch块只会处理一个例外。如果在块中构造了两个或多个类型为A的对象,则每个对象的析构函数都将抛出异常。抛出的第一个异常(从最后创建的对象/先破坏的)可以得到处理。但是,在到达处理程序之前,将销毁所有其他本地对象。当块中有另一个A对象时,它也会被销毁,抛出异常,瞧,有两个例外。当析构函数外有两个未处理的异常时,系统会调用需要终止程序的std::terminate()

使用C ++ 11,所有析构函数都被隐式定义为noexceptnoexcept(true)(两者都是等价的)。这种改变的原因是默认情况下构建和销毁临时移动应该是noexcept。如果你想用C ++ 11抛出析构函数,你需要将析构函数声明为noexcept(false),例如:

class A {
public:
    ~A() noexcept(false) { throw std::exception(); } // still a Bad Idea!!!
    // ...
};

当从析构函数中抛出异常时,您实际上需要确保在处理现有异常时,对象不会因为堆栈展开而被销毁。在析构函数中,只要没有异常逃避析构函数,就可以有异常。

实际上,没有安全的方法来了解对象是否因堆栈展开而被销毁。虽然从语言的角度来看是合法的,但最好不要从析构函数中抛出。