Bla*_*ger 6 c++ exception language-lawyer noexcept
有些函数应该是非抛出的,但标准对此没有任何说明。例如erase(q)(q表示有效的可解引用常量迭代器)的关联容器。根据[res.on.exception.handling#4],这允许实现抛出任何标准异常:
C++ 标准库中定义的函数没有 Throws: 段落,但具有潜在抛出异常规范,可能会抛出实现定义的异常。170 实现应通过抛出标准异常类或派生自标准异常类的异常来报告错误([坏.alloc]、[support.exception]、[std.exceptions])。
因此,如果您想吞掉它们抛出的任何实现定义的异常,则必须使用 try-catch 块。
std::set<int> s{1};
try
{
s.erase(s.cbegin());
}
catch (...) {}
Run Code Online (Sandbox Code Playgroud)
它丑陋且低效,但却是必要的。所以我也不知道这样做有什么好处。
这是一篇论文(被其他一些标准库提案引用),原因是未指定noexcept某些标准库函数:N3248:noexcept阻止库验证
如果标准规定不引发任何异常的函数确实引发了异常,则您已进入未定义的行为领域。您的代码中有一个错误。抓住并吞下它当然不是正确的做法。
例如在这段代码中:
std::set<int> s;
try
{
s.erase(s.cbegin());
}
catch (...) {}
Run Code Online (Sandbox Code Playgroud)
可能会s.erase在调试模式下抛出 C++ 异常,因为不满足先决条件(s.cbegin()不可取消引用),从而使其运行并且似乎工作不被注意,但在发布模式下突然发生一些其他行为(例如崩溃或无限循环)。
如果标准强制要求该函数为noexcept,则该函数即使在调试模式下也不能抛出异常。
noexcept然而,即使标准中没有明确说明,标准库也可以添加说明符,许多标准库都是这么做的。这为标准库实现者提供了执行适当操作的自由(例如,noexcept(true)in <release_set>,but noexcept(false)in <debug_set>)
当然,如果您知道满足先决条件(例如if (!s.empty()) s.erase(s.cbegin());),您就知道不能引发异常,并且不需要编写任何异常处理。
另请参阅:为什么向量访问运算符没有指定为 noexcept?