noexcept修饰符,noexcept操作符
noexcept的两个作用:
1)作为noexcept修饰符,声明函数是否抛出异常;
2)作为noexcept操作符,判断表达式是否抛出异常;
noexcept修饰符
noexcept修饰符有两种形式:一种是简单在函数声明后加noexcept,另一种是接受一个常量表达式作为参数,如:
void except_func() noexcept; // 这里noexcept作为修饰符
void except_func() noexcept(常量表达式); // 这里noexcept作为运算符
声明为noexcept的函数抛出了异常,会怎么样?
如果一个函数声明为noexcept,但还是抛出了异常,会直接调用std::terminate中断程序的执行。
注:C++98中,用throw()来声明不抛出异常,throw(异常类型)声明可能抛出的异常类型。noexcept效率比throw更高一些,因为编译器可以用std::terminate()来终止程序运行,而throw异常机制会有一些额外开销,如函数栈依次展开并析构自动变量。
例1,C++98中,用throw()声明不抛出异常的函数:
template<class T> class A{
public:
static constexpr T min() throw() { return T(); }
static constexpr T max() throw() { return T(); }
static constexpr T lowest() throw() { return T(); }
...
};
相应地,在C++11中,使用noexcept替换throw()
template<class T> class A{
public:
static constexpr T min() noexcept { return T(); }
static constexpr T max() noexcept { return T(); }
static constexpr T lowest() noexcept { return T(); }
...
};
noexcept操作符
noexcept普通形式
noexcept(e);
可以让一个函数f()是否抛出异常,与另一个函数g()保持一致:
void f() noexcept(noexcept(g())); // f和g的异常说明保持一致
改写成让f()是否抛出异常,取决于模板参数T()表达式:
template<class T>
void f() noexcept(noexcept(T())) { }
例2,C++98中,用throw()声明可能抛出std::bad_alloc异常的函数:
void* operator new(std::size_t) throw(std::bad_alloc);
void* operator new[](std::size_t) throw(std::bad_alloc);
相应地,C++11中,可用noexcept(false)来替代throw
void* operator new(std::size_t) noexcept(false);
void* operator new[](std::size_t) noexcept(false);
可以看到,noexcept声明函数可能抛出的异常时,无需指明具体的类型,而throw却需要指明。
不过,出于安全考虑,C++11标准中,类的析构函数默认是noexcept(true)。如果显示指定noexcept或noexcept(false),就不会再保持默认值。
参考
[1]MichaelWon, IBM XL编译器中国开发团队. 深入理解C++11:C++11新特性解析与应用[M]. 机械工业出版社, 2013.