在什么情况下C ++编译器推断noexcept?

时间:2017-11-13 14:03:28

标签: c++ exception compiler-optimization noexcept

假设C ++编译器正在编译一个函数,该函数的定义在与其调用相同的转换单元中可用。假设它不会抛出自身,也不会调用已知的抛出函数。假设也没有调用extern C代码,也不会调用具有潜在零值的数字除法。

在这些假设下,编译器会将函数视为noexcept吗?如果没有,是否有推断noexcept的其他条件?

具体来说,如

这样的超简单功能呢?
void foo() { } /* this one */
class A { 
    int x_; 
public: 
    x() const { return x_; }  /* ... and this one */
}

我想要的答案仅基于标准,最重要的,也可能是GCC和clang所做的。

1 个答案:

答案 0 :(得分:5)

除非您明确使用noexcept说明符,否则几乎所有函数都可能被抛出。例外情况是您自己对delete(释放函数)的定义,以及一些特殊的成员函数:构造函数,析构函数和赋值运算符。 (C ++ 17)

来自[except.spec]

  

如果函数的声明没有 noexcept-specifier ,则声明可能会抛出   异常规范,除非它是析构函数或释放函数或在其第一个声明中是默认的,   在这种情况下,异常规范如下所述,该函数的其他声明均不应如此   有一个 noexcept-specifier

构造

隐式noexcept除非为任何成员(或成员的成员等)执行任何初始化,否则可能会抛出

析构

隐式noexcept除非潜在构造的子对象的任何析构函数可能抛出。

分配运营商

隐式noexcept,除非任何使用内部分配都可能被抛出。

以下是一些演示上述内容的示例代码(clang 6.0.0gcc 8.0.0):

int foo() { return 1; }
int bar() noexcept{ return 1; }

struct Foo{};

struct Bar{
 Bar(){}
};

int main()
{
    static_assert(noexcept(bar()));
    static_assert(!noexcept(foo()));
    static_assert(noexcept(Foo()));
    static_assert(noexcept(Foo().~Foo()));
    static_assert(noexcept(Foo().operator=(Foo())));
    static_assert(!noexcept(Bar()));
    Bar b;
    static_assert(noexcept(b.~Bar()));
}

使用=default或允许编译器通过省略生成自己特殊成员函数版本的另一个原因。