从代码编写伦理角度,能否为可能触发UB的函数添加noexcept(true)?
自定义迭代器
C::f()是否添加noexcept(true)的伦理讨论 代码示例
struct A { int* a_ptr; }; struct B { A* b_ptr; }; struct C { // iterator B* c_ptr; //... int& f() noexcept(?) { // provides some access if 'C' is valid return c_ptr->b_ptr->a_ptr; } };
场景说明
C是某自定义迭代器,在其关联容器未被销毁前始终有效;若容器已销毁,调用
C::f将触发未定义行为(UB)。我们信任用户不会在创建C并销毁容器后调用C::f(会提前警告此为不良实践)。
问题
从代码编写伦理的角度出发,是否可以为
f()添加noexcept(true)?需要给出支持任一决策的理由。
支持添加noexcept(true)的理由
- 契合约定与信任前提:既然已经明确告知用户“容器销毁后调用
f()是违规操作且会引发UB”,并且信任用户会遵守这一规则,那在合法使用场景下,f()的逻辑(连续指针解引用)本身不会抛出C++标准异常——合法内存访问时的指针解引用不属于异常触发场景,UB带来的问题也不在标准异常体系内。标注noexcept(true)不仅能让编译器生成更高效的代码,还能明确合法使用时的异常承诺,是对遵守约定用户的负责任表现。 - 遵循迭代器行业惯例:标准库迭代器的核心访问函数(比如
operator*)大多都标注了noexcept,因为它们的合法访问逻辑本身不会抛出异常。自定义迭代器对齐这一惯例,能让用户的使用体验保持一致,不用额外处理不必要的异常逻辑,这也是代码伦理里“降低用户使用成本、遵循通用规范”的体现。
反对添加noexcept(true)的理由
- 异常承诺需保持严谨:
noexcept(true)的字面意思是“无论任何情况都不会抛出异常”,但实际上用户违反约定时,UB可能导致程序崩溃、数据破坏等不可控结果——虽然这些不是标准C++异常,但标注noexcept(true)可能会让用户误以为函数在所有场景下都安全,间接削弱了“不良实践”的警告力度。从代码伦理的严谨性来说,不应做出超出自己可控范围的承诺。 - 避免误导后续维护者:后续接手代码的开发者可能不知道“信任用户不违规调用”这个前提,看到
noexcept(true)会默认函数在所有调用场景下都不会出异常,进而在修改代码时忽略风险,甚至依赖这个标注做错误的逻辑设计。这违背了代码伦理中“清晰传递代码边界与风险”的基本原则。
内容的提问来源于stack exchange,提问作者Alexander S
相关产品推荐
相关产品推荐

