是的,这看起来像是标准的缺陷。对于重新抛出的 throw 表达式,即throw;
没有操作数,15.1p8 说:
没有操作数的throw 表达式重新抛出当前处理的异常。使用现有的异常对象重新激活异常;没有创建新的异常对象。[...]
那是:
#include <exception>
#include <cassert>
int main() {
std::exception *p = nullptr;
try {
try {
throw std::exception();
} catch(std::exception &ex) {
p = &ex;
throw;
}
} catch(std::exception &ex) {
assert(p == &ex);
}
}
如果实现current_exception
复制当前处理的异常对象,没有办法判断是否rethrow_exception
复制,但是如果它引用了异常对象,那么我们可以检查:
#include <exception>
#include <iostream>
int main() {
std::exception_ptr p;
try {
try {
throw std::exception();
} catch(...) {
p = std::current_exception();
std::cout << (p == std::current_exception()) << ' ';
std::rethrow_exception(p);
}
} catch(...) {
std::cout << (p == std::current_exception()) << '\n';
}
}
我在 prints 上尝试过的每个实现1 1
;0 0
允许current_exception
复制;0 1
显然是不可能的,而目前的标准似乎要求1 0
. 修复将使用类似于 15.1p8 的语言对 18.8.5p10 进行澄清,允许或强制rethrow_exception
不复制exception_ptr
.
大多数Throws:标准中的规范只是命名一个类型(Throws:bad_alloc
)或使用不定冠词(Throws: an exception of type ...);唯一使用定冠词的其他异常规范是future::get
and shared_future::get
,因此任何解决方案都应该解决这些问题。