【问题标题】:Why is it allowed to throw an exception inside a noexcept-tagged function?为什么允许在带有 noexcept 标记的函数中抛出异常?
【发布时间】:2016-07-23 10:29:03
【问题描述】:

我很难理解这一点。

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

这在clang中编译得很好(我没有检查gcc),但对我来说似乎是无稽之谈。为什么编译器会允许 noexcept 函数包含 throw 语句?

【问题讨论】:

  • 抱歉,标题有误导性。真正的问题当然是“为什么编译器允许 noexcept 函数包含 throw 语句?”。

标签: c++ exception compilation tags noexcept


【解决方案1】:

将会发生什么是std::terminate() 被触发,因为您的异常规范不允许这种情况发生(请参阅[except.spec/9])。

至于为什么允许这样做,根本不可能彻底检查是否有任何违反规范的内容。考虑类似的事情:

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

f可以扔吗?不能说。

【讨论】:

  • 在您的示例中,f 未使用 noexcept 规范声明,因此它可能会抛出。编译器可以检测到这一点。它实际上做了与 const 正确性类似的事情。为什么对于 noexcept 也不能​​这样做?
  • @Calmarius 定义类似。如果您调用非noexcept 函数,您希望它不编译
  • 至少有警告。在不允许抛出的函数中调用抛出函数是一个编程错误,应该在编译时捕获。
  • @Calmarius 这真的不是编程错误。您可以确保潜在抛出的函数不会以其他方式抛出。或者可能抛出的函数无论如何都不会抛出,并且只是在 C++11 之前编写的。
  • 然后将 noexcept 传播到那些不会抛出的函数。用 try-catch(...) 块包围有时抛出的函数,以明确表示您希望阻止来自违规函数的异常传播。这基本上就是 Java 对其检查异常所做的事情。
【解决方案2】:

有可能一个声称不抛出的函数实际上会抛出。
如果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 对于让编译器为乞讨者做一些效率改进很有用。这将是你信守承诺的场景。没有 noexcept 的函数可以抛出异常,其他的不能。如果您将它们混合在一起(例如从noexcept 函数中抛出),编译器只会使程序崩溃以拯救您吗? terminate() 是您这样做时应该高兴的事情吗?当程序调用terminate() 时还不是runtime
猜你喜欢
  • 2015-05-12
  • 2020-09-10
  • 2016-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-03
  • 1970-01-01
相关资源
最近更新 更多