为什么 std::uncaught_exception 会变成 std::uncaught_exceptions

Why will std::uncaught_exception change to std::uncaught_exceptions?

本文关键字:uncaught std exceptions 为什么 exception      更新时间:2023-10-16

我刚刚注意到

http://en.cppreference.com/w/cpp/error/uncaught_exception

C++17 将返回一个boolstd::uncaught_exception() 替换为返回intstd::uncaught_exceptions()

描述这一点的标准的补充如下:

http://isocpp.org/files/papers/n4259.pdf

它没有提供基本原理,但它确实说

[注意:当 uncaught_exceptions()> 0 时,抛出异常可以 导致调用 std::terminate() (15.5.1)。– 尾注]

这很奇怪地含糊不清。

这种变化的原因是什么?在 C++17 或标准的未来版本中是否可能出现多个活动异常?

介绍这一点的论文是 n4152,它有基本原理(通常归结为"使 ScopeGuard 工作")

引用,

正如至少自 1998 年以来在 Guru of the Week #47 中记录的那样,这意味着从析构函数(本身可以在堆栈展开期间调用)传递调用的代码无法正确检测它本身是否实际上被调用为展开的一部分。一旦你解除任何异常,uncaught_exception一切看起来都像是展开,即使有多个活动异常。

这使用主要实现中已经存在的信息,其中 ScopeGuard 的当前实现诉诸于非可移植代码,这些代码依赖于未记录的编译器功能,以使 ScopeGuard 今天"在实践中可移植"。此选项建议添加一个新函数来公开编译器中已经存在的信息,以便这些用途可以真正移植。

PS:下面是如何使用编译器专用信息实现此函数的示例: https://github.com/panaseleus/stack_unwinding/blob/master/boost/exception/uncaught_exception_count.hpp

对于使用它的简单示例,只需看看 boost.log 的"记录泵"(请参阅 boost/log/detail/format.hpp 和 boost/log/sources/record_ostream.hpp):如果 foo 不抛出,也就是说,如果调用析构函数时飞行中的异常数不大于调用构造函数时,BOOST_LOG(lg) << foo();可以登录它创建的 guard 对象的析构函数。

std::uncaught_exception() 仅检测堆栈是否正在展开。在赫伯·萨特(Herb Sutter)的一篇论文中,他指出,这并不能可靠地表明存在活跃的例外。赫伯认为这"几乎"有用。我遇到过这种情况,这确实是模棱两可的,这就是导致我写这篇文章的原因。

std::uncaught_exceptions() 被指定为返回活动异常的数量,这实际上很有用。