可以rethrow_exception真的抛出相同的异常对象,而不是副本吗?

sou*_*lie 7 c++ language-lawyer c++11

在研究内容时exception_ptr,C++ 11标准说(18.8.5/7):

在引用同一异常对象的exception_ptr对象上使用rethrow_exception不应引入数据争用.[注意:如果rethrow_exception重新抛出相同的异常对象(而不是副本),对该重新抛出的异常对象的并发访问可能会引入数据争用......

我没有找到这种奇怪的"注释"适用的情况,因为所描述的效果rethrow_exception是"抛出:p引用的异常对象"但是15.1/3,描述了抛出异常副本的一般异常抛出过程强制要求 - 初始化一个临时对象,称为异常对象."

奇怪的说明意味着rethrow_exception会跳过此复制初始化.但这真的有可能吗?

eca*_*mur 3

是的,这看起来像是标准的缺陷。对于重新抛出的 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);
   }
}
Run Code Online (Sandbox Code Playgroud)

如果 的实现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';
   }
}
Run Code Online (Sandbox Code Playgroud)

我在印刷品上尝试过的每一个实现1 10 0如果是复印件则允许current_exception0 1显然是不可能的,而目前的标准似乎要求1 0。修复方法是使用类似于 15.1p8 的语言对 18.8.5p10 进行澄清,允许或强制rethrow_exception不复制exception_ptr.

大多数抛出:标准中的规范仅命名类型(抛出:)bad_alloc或使用不定冠词(抛出:类型的异常...);使用定冠词的唯一其他异常规范是 和 的规范future::getshared_future::get因此任何解决方案都应该解决这些问题。