CppCoreGuidelines F.6 如果函数不能抛出异常,声明为 noexcept
F.6: If your function must not throw, declare it noexcept
理由
如果代码中不打算抛出异常,程序里也不打算处理异常,可以直接终止这个程序。声明一个函数为 noexcept
可以让编译器优化生成的二进制、并且可以减少执行路径,加快错误时的退出速度。
例子
把不支持异常的 C 或其他语言实现的函数标注为 noexcept
。C++ 标准库默认所有 C 标准库函数为 noexcept
。
注意
constexpr
函数在运行时计算可能会抛出异常,所以某些情况可以 noexcept
。根据条件判断是否抛出异常。
例子
我们甚至可以在可能抛出异常的函数上添加 noexcept
标签。
vector<string> collect(istream& is) noexcept { vector<string> res; for (string s; is >> s;) res.push_back(s); return res; }
collect
运行时如果内存不足,程序直接退出。除非程序设计好能处理内存耗尽的情况。终止函数terminate()
可能会产生一个错误日志信息。
例子
我们首先定义一个函数,抛出一个异常:
void throw_err() { throw 1; }
然后,定义个没有标记 noexcept
的函数调用 throw_err
:
void throw_err() { throw 1; } void no_block_throw() { throw_err(); } int main() { try { no_block_throw(); } catch(int i) { cout << i << endl; } return 0; }
异常成功捕捉:
1
在定义一个有 noexcept
的函数:
void throw_err() { throw 1; } void block_throw() noexcept { throw_err(); } int main() { try { block_throw(); } catch(int i) { cout << i << endl; } return 0; }
程序直接终止:
terminate called after throwing an instance of 'int'
注意
在决定是否用 noexcept
前,要评估程序的执行环境,是否有异常抛出和内存分配的问题。某些执行环境能处理分配异常bad_alloc
等,标准库可以抛出异常。但是很多执行环境,无法正常处理异常,最直接最简单的办法就是终止程序。如果代码无法处理内存分配错误,最好的办法就是给可能导致内存分配错误的函数添加 noexcept
。
换句话说,如果能处理好异常的情况的话,就不要加 noexcept
。
noexcept
主要用于底层函数。
注意
析构函数、数据交换函数、转移操作还有默认析构函数不可抛出异常。
加强
- 标注不能抛出异常,但是没有声明
noexcept
的函数 - 标注不该抛出异常却抛出异常的交换、转移、析构函数、默认析构函数