带默认参数构造的函数应标记noexcept还是noexcept(noexcept(Item()))?
关于函数
test的noexcept说明符选择 首先直接给结论:你应该使用noexcept(noexcept(Item())),而非单纯的noexcept,具体原因和标准依据如下:
- 你提到参数传递(即把
Item()生成的临时对象绑定到const Item&引用)不会抛出异常,但默认参数的初始化过程——也就是Item()的默认构造——仍可能存在抛出异常的风险。如果直接标记函数为noexcept,那么当Item()构造抛出异常时,程序会直接调用std::terminate()强制终止,这显然不符合异常安全的预期。 - 而
noexcept(noexcept(Item()))是条件性异常说明符:它会动态匹配Item()的异常属性。如果Item的默认构造函数本身是noexcept的,那么test函数会被视为noexcept;如果Item()可能抛出异常,test函数也会允许异常传播(不会触发终止),这才是贴合实际执行逻辑的正确写法。
标准引用依据
根据C标准(以C17为例):
在[except.spec]/12中明确:带显式异常说明符
noexcept(constant-expression)的函数,仅当常量表达式求值为false时才允许抛出异常。
同时,[dcl.fct.default]/10规定:当函数调用使用默认实参时,默认实参的初始化是函数调用的一部分,因此函数的异常说明符必须覆盖默认实参初始化过程中可能发生的异常。
简单来说:函数的异常规格需要覆盖整个调用流程中的所有操作,包括默认参数的初始化。如果默认参数的构造存在抛异常的可能,函数不能无条件标记为noexcept,而应该用条件式的noexcept来适配默认构造函数的异常属性。
另外,如果你能确定Item()的默认构造永远不会抛出异常(比如Item的默认构造已经标记为noexcept),那么两种写法效果一致,但后者更具维护性——后续若Item默认构造的异常属性发生变化,test函数的noexcept说明符会自动适配,无需手动修改。
内容的提问来源于stack exchange,提问作者dodomorandi
相关产品推荐
相关产品推荐

