从 noexcept 函数参数的构造函数中抛出的异常会立即导致对 std::terminate() 的调用吗?

Will an exception thrown from a noexcept function parameter's constructor immediately result in a call to std::terminate()?

给定以下 class 声明:

class phone_number
{
public:
    explicit phone_number( std::string number ) noexcept( std::is_nothrow_move_constructible< std::string >::value );
}

phone_number::phone_number( std::string number ) noexcept( std::is_nothrow_move_constructible< std::string >::value )
    : m_originalNumber{ std::move( number ) }
{

}

如果从字符串构造函数中抛出异常,由于 noexcept 规范,以下代码行是否会立即调用 std::terminate()

const phone_number phone("(123) 456-7890");

由于所有参数都在之前调用函数,因此参数的构造函数发出的异常不会违反函数本身的noexcept契约。

为了证实这一点,这是我尝试过的,近似于您的示例:

class A
{
public:
    A(const char *)
    {
        throw std::exception();
    }
};

void f(A a) noexcept
{

}

int main()
{   
    try
    {
        f("hello");
    }
    catch(std::exception&)
    {
        cerr<< "Fizz..." << endl;
    }
    return 0;
}

不出所料,输出是Fizz...,程序正常退出。

C++有两种异常规范:

动态异常规范(已弃用)

看起来像这样:

void foo() throw(x, y, z)

在这种情况下,如果在 foo 中抛出一个不在集合 x、y 或 z 中的异常,则调用 std::unexpected()。默认情况下,这将调用 std::terminate() 但您可以通过设置自己的意外处理程序来进行干预,它甚至可能抛出 x、y 或 z 以允许程序继续。当然,从来没有人这样做过。

noexcept-specification(自 c++11 起)

看起来像这样:

void foo() noexcept; // same as noexcept(true)
void foo() noexcept(true); // not allowed to throw exceptions
void foo() noexcept(false); // allowed to throw exceptions

这是有趣的地方,因为如果 foo() noexcept(true) 确实抛出异常,行为是 不同的 。标准规定应调用 std::terminate()

您没有机会捕获异常或以其他方式纠正这种情况。庄严的承诺被兑现和打破 - 节目结束。

来自 §15.4 [except.spec]

10 Whenever an exception of type E is thrown and the search for a handler (15.3) encounters the outermost block of a function with an exception specification that does not allow E, then,

(10.1) — if the function definition has a dynamic-exception-specification, the function std::unexpected() is called (15.5.2),

(10.2) — otherwise, the function std::terminate() is called (15.5.1)