为什么一些C++标准函数缺少文字异常规范?

6
有些函数应该是非抛出异常的,但标准没有提及。例如,关联式容器中的erase(q)(其中q表示一个有效的可以解引用的常量迭代器)。根据[res.on.exception.handling#4],这允许实现抛出任何标准异常:

在C++标准库中定义了没有Throws段落但具有潜在抛出异常规范的函数可能会抛出实现定义的异常。 170实现应通过抛出标准异常类([bad.alloc],[support.exception],[std.exceptions])或派生自它们的异常来报告错误。

如果你想要吞咽它们抛出的任何实现定义的异常,你必须使用try-catch块。
std::set<int> s{1};
try
{
    s.erase(s.cbegin());
}
catch (...) {}

这很丑陋且效率低下,但却是必要的。因此我也不知道它有什么好处。


这些函数具有较窄的合约,它们的输入必须符合前置条件,否则行为将是未定义的。您不应该假装它们会抛出异常,而是确保满足它们的前置条件。 - StoryTeller - Unslander Monica
@StoryTeller - 不诋毁Monica,所以如果我满足条件,我可以忽略它们是否抛出异常,然后做任何我想做的事情吗? - Blackteahamburger
1
如果符合条件,函数应执行其规定的操作。我不明白你所说的“忽略”和“随意”。应用程序应处理异常,但将每个操作包装在try中并非解决方法。 - StoryTeller - Unslander Monica
@StoryTeller - 不要诽谤Monica,谢谢。我误解了你的意思。 - Blackteahamburger
请将以下与编程相���的内容从英语翻译成中文。仅返回翻译后的文本:请勿在问题正文中添加答案。相反,您应该将其作为答案添加。允许并鼓励回答自己的问题 - Adriaan
@Adriaan 我刚刚将问题的这一部分标记为已解决...我无法给出答案... - Blackteahamburger
1个回答

5
这里有一篇论文(被其他标准库提议引用)介绍了不在某些标准库函数上指定noexcept的原因:N3248: noexcept Prevents Library Validation 如果一个标准规定不会抛出任何异常的函数确实抛出了异常,则进入了未定义行为的领域。这是您代码中存在的错误。捕获并忽略它肯定不是正确的做法。
例如,在以下代码中:
std::set<int> s;
try
{
    s.erase(s.cbegin());
}
catch (...) {}

在调试模式下,由于未满足前提条件(s.cbegin() 无法被解引用),可能会使得 s.erase 抛出 C++ 异常,这样程序似乎可以正常运行但并不会被察觉,而在发布模式下则会发生其他意外情况,例如崩溃或无限循环等。
如果标准规定该函数为 noexcept,即使在调试模式下该函数也不能抛出异常。
然而,标准库允许添加 noexcept 规范,即使标准中未明确声明,很多标准库都这么做了。这给了标准库实现者自由选择合适的方式(如在 <release_set> 中使用 noexcept(true),而在 <debug_set> 中使用 noexcept(false))。
当然,如果你知道前提条件已满足(如 if (!s.empty()) s.erase(s.cbegin());),你就知道不会抛出异常,不需要编写任何异常处理代码。
另请参阅:为什么 vector 访问操作符没有指定为 noexcept?

我明白。但是你没有解释为什么erase(k)没有noexcept,它不会导致未定义的行为。 - Blackteahamburger
@Blackteahamburger 我举了一个例子,说明它确实会发生这种情况(例如,给它结束迭代器、给它另一个容器的迭代器,或者其他地方的 UB 打破了集合的内部结构并被检测到)。 - Artyer
@Blackteahamburger 即使 < 被标记为 noexcept,如果 erase 检测到 < 不形成有效的全序关系(UB),或者由于其他 UB 破坏了容器之前的某些操作,它仍可能失败。此外,当库在非调试模式下构建时,它们通常被标记为 noexcept。标准允许但不强制要求这样做。 - Artyer
因此,可以使用更严格的条件noexcept说明符。 - Blackteahamburger
@Blackteahamburger,看起来N3248并不建议在先前的UB情况下删除noexcept。但是erase仍然要求您传递的对象是您比较对象的弱排序的一部分。 - Artyer
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接