noexcept

Version >= C++ 11

  1. 一元运算符,用于确定对其操作数的求值是否可以传播异常。请注意,不检查被调用函数的主体,因此 noexcept 可以产生错误否定。不评估操作数。

    #include <iostream>
    #include <stdexcept>
    void foo() { throw std::runtime_error("oops"); }
    void bar() {}
    struct S {};
    int main() {
        std::cout << noexcept(foo()) << '\n'; // prints 0
        std::cout << noexcept(bar()) << '\n'; // prints 0
        std::cout << noexcept(1 + 1) << '\n'; // prints 1
        std::cout << noexcept(S()) << '\n';   // prints 1
    }
    

    在这个例子中,即使 bar() 永远不会抛出异常,noexcept(bar()) 仍然是假的,因为 bar() 无法传播异常这一事实尚未明确指定。

  2. 声明函数时,指定函数是否可以传播异常。单独地,它声明该函数不能传播异常。使用带括号的参数,它声明函数可以或不可以根据参数的真值传播异常。

    void f1() { throw std::runtime_error("oops"); }
    void f2() noexcept(false) { throw std::runtime_error("oops"); }
    void f3() {}
    void f4() noexcept {}
    void f5() noexcept(true) {}
    void f6() noexcept {
        try {
            f1();
        } catch (const std::runtime_error&) {}
    }
    

    在这个例子中,我们声明 f4f5f6 不能传播异常。 (虽然在执行 f6 期间可以抛出异常,但它被捕获并且不允许传播出函数。)我们已经声明 f2 可能传播异常。当 noexcept 说明符被省略时,它相当于 noexcept(false),所以我们隐含地声明 f1f3 可以传播异常,即使在执行 f3 期间实际上不能抛出异常。

Version >= C++ 17

函数是否为 noexcept 是函数类型的一部分:即,在上面的示例中,f1f2f3 具有与 f4f5f6 不同的类型。因此,noexcept 在函数指针,模板参数等方面也很重要。

void g1() {}
void g2() noexcept {}
void (*p1)() noexcept = &g1; // ill-formed, since g1 is not noexcept
void (*p2)() noexcept = &g2; // ok; types match
void (*p3)() = &g1;          // ok; types match
void (*p4)() = &g2;          // ok; implicit conversion