异常行为 C++14 与 C++98

Exception behavior C++14 vs C++98

我写了下面的程序

#include <iostream>
#include <stdexcept>

class Myclass
{
    public:
    ~Myclass() 
    {
        //throw std::runtime_error("second (in destructor)");
        throw 1;
    }
};

void fun()
{
    Myclass obj;
}
int main()
{   
    try
    {
        fun();      
    }
    catch (const std::exception& e)
    {
       std::cout << e.what();
    }
    catch(...)
    {
       std::cout << " ... default Catch" << std::endl; 
    }
    std::cout << "Normal" << std::endl;
    return 0;
}  

当我 运行 上面的程序在 C++98 模式下 (cpp.sh) 它打印

 ... default Catch
Normal

当我运行它使用C++14模式时,它不打印任何东西。 为什么此行为会发生变化?

我确实理解,每当发生任何异常并且任何 destructor(在堆栈展开过程中)抛出任何异常时,它都会终止应用程序。但是这里只有一次异常从来自 destructor.

try 块抛出

自 C++11 起,没有明确说明异常规范的析构函数与默认生成的异常规范具有相同的异常规范。在您的情况下,默认生成的析构函数将是 noexcept (大多数默认生成的析构函数是),因此您的析构函数也被视为 noexcept 。从 noexcept 函数中抛出会自动调用 std::terminate.

如果您希望异常可捕获,请将析构函数声明为抛出:

~Myclass() noexcept(false)
{
    //throw std::runtime_error("second (in destructor)");
    throw 1;
}

但在你这样做之前,重新考虑一下。这是一个 bad idea to have throwing destructors

从析构函数中抛出异常总是一个坏主意,因为如果已经存在异常(例如,在堆栈展开期间调用析构函数),std::terminate 将被调用。

也就是说,C++11 向析构函数添加了一个隐式 noexcept(true)(下面列出的情况除外),这意味着,如果从 noexcept(true) 析构函数中抛出,则再次 std::terminate

§12.4/3

[class.dtor] [ Note: A declaration of a destructor that does not have a noexcept-specifier has the same exception specification as if had been implicitly declared (15.4). — end note ]

和§15.4/14

[except.spec] The exception specification for an implicitly-declared destructor, or a destructor without a noexcept-specifier, is potentially-throwing if and only if any of the destructors for any of its potentially constructed subojects is potentially throwing.

我强烈建议重组您的代码,以便不会 抛出析构函数。