std::async 如何"store"任意异常?

How does std::async "store" an arbitrary exception?

本文关键字:异常 任意 store 如何 std async      更新时间:2023-10-16

我无法理解std::async如何存储任何异常,而不仅仅是从std::exception派生的异常。我玩了下面的代码

#include <iostream>
#include <future>
#include <chrono>
void f()
{
    std::cout << "ttIn f() we throw an exception" << std::endl;
    throw 1; // throw an int
}
int main()
{
    std::future<void> fut = std::async(std::launch::async, f);
    std::cout << "Main thread sleeping 1s..." << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1)); // sleep one second
    std::cout << "Main thread waking up" << std::endl;
    try
    {
        fut.get();
    }
    catch(...)
    {
        std::cout << "We caught an exception!" << std::endl;
        throw; // rethrow
    }
}

我异步启动f(),然后在f中抛出一个int。神奇的是,这个intstd::async返回的future捕获并存储。我知道catch(...)可以在std::async中存储异常,但后者如何在不知道异常类型的情况下存储它?异常不是从某个基类派生的(在这种情况下,可能可以通过某个Base::clone"克隆"它),但可以是任何异常。我们能神奇地"推导"出异常类型吗?

总之,我的问题是:

在不知道异常类型的情况下,我们如何将任意异常存储在对象中,然后在以后的某个时间重新抛出它?

std::async可以在std::threadstd::packaged_task之上实现。

CCD_ 14可以(部分)在CCD_ 15和相关函数(线程退出准备函数除外)之上实现。

CCD_ 16及相关函数不能用C++编写。

我不确定这是否能准确回答您的问题,但这个例子可能会有所帮助。

我编译了以下内容:

int main()
{
    throw 1;
}

使用命令

g++ -fdump-tree-gimple -std=c++11 main.cpp -o main

万向节(gcc的中间输出)是:

int main() ()
{
  void * D.1970;
  int D.1974;
  D.1970 = __cxa_allocate_exception (4);
  try
    {
      MEM[(int *)D.1970] = 1;
    }
  catch
    {
      __cxa_free_exception (D.1970);
    }
  __cxa_throw (D.1970, &_ZTIi, 0B);
  D.1974 = 0;
  return D.1974;
}

所以它用一个表示类型的符号的地址来调用__cxa_throw。在这种情况下,类型是_ZTIi,它是整数的损坏类型。

编译时不可用的类型

类型符号只需要在运行时可用。在一个试图隐藏尽可能多的符号的动态库中,它需要确保任何没有在内部捕获和处理的异常都是可用的。有关更多信息,请参阅https://gcc.gnu.org/wiki/Visibility特别是Problems with C++ exceptions (please read!)

看看这在使用不同命名方案的编译器编译的动态库之间是如何工作的,会很有趣。