从 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)
给定以下 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)