C++ 为什么允许在noexcept标记的函数中抛出异常?

C++ 为什么允许在noexcept标记的函数中抛出异常?,c++,exception,compilation,tags,noexcept,C++,Exception,Compilation,Tags,Noexcept,我很难理解这一点 double compute(double x, double y) noexcept { if (y == 0) throw std::domain_error("y is zero"); return x / y; } 这在铿锵中编译得很好(我没有检查gcc),但在我看来这似乎是胡说八道。为什么编译器会允许noexcept函数包含throw语句?将触发std::terminate(),因为您的异常规范不允许这种情况发生(请参阅) 至于为什么允许这

我很难理解这一点

double compute(double x, double y) noexcept
{
   if (y == 0)
       throw std::domain_error("y is zero");
   return x / y;
}

这在铿锵中编译得很好(我没有检查gcc),但在我看来这似乎是胡说八道。为什么编译器会允许noexcept函数包含throw语句?

将触发
std::terminate()
,因为您的异常规范不允许这种情况发生(请参阅)

至于为什么允许这样做,根本不可能彻底检查是否有任何东西违反了规范。考虑一下:

double f(double );
double compute(double x, double y) noexcept
{
    return x / f(y);
} 

能抛出吗?不能说。

声明不抛出的函数可能实际上抛出。
如果
noexcept
函数确实抛出,则调用
terminate
,从而强制执行在运行时不抛出的承诺

// The compiler does not check the `noexcept` specification at compile time.
void f() noexcept // Promises to not throw any exception
{
    throw runtime_error("error"); // Violates the exception specification
}
指定一个函数不会抛出,可以向非抛出函数的调用者保证他们永远不需要处理异常


要么函数不会抛出,要么整个程序将终止。

对不起,标题有误导性。真正的问题当然是“为什么编译器会允许noexcept函数包含throw语句?”。在您的示例中,
f
不是用
noexcept
规范声明的,因此它可能会抛出。编译器可以检测到这一点。它实际上做了一些与常量正确性类似的事情。“为什么它不能对noexcept也这样做呢?”Calmarius这样定义。如果调用一个非
noexcept
函数,您至少希望它不会编译。在不允许抛出的函数中调用抛出函数是一个编程错误,应该在编译时捕获。@Calmarius这实际上不是一个编程错误。您可以确保潜在抛出函数不会以其他方式抛出。或者,潜在的抛出函数无论如何都不会抛出,只是在C++11之前编写的。然后将noexcept传播到那些不会抛出的函数。用try-catch(…)块包围有时抛出的函数,使其显式化。如果要阻止有问题的函数的异常传播,请使用该块。这基本上就是Java在检查异常时所做的。因此,
noexcept
对于让编译器为请求者做一些效率改进是很有用的。这就是你信守诺言的情景。没有noexcept的函数可以抛出异常,而其他函数则不能。如果您混合了它们(例如从
noexcept
函数抛出),编译器只会为了保存您而使程序崩溃
terminate()
这样做应该让您感到高兴吗?当程序调用
terminate()
时,运行时是否已经存在?