我无法理解std::async
如何存储任何异常,而不仅仅是std::exception
派生的异常。我玩了下面的代码
#include <iostream>
#include <future>
#include <chrono>
void f()
{
std::cout << "\t\tIn 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()
,然后在int
内抛出f
。奇怪的是,这个int
被std::async
返回的未来捕获并存储。我理解catch(...)
中的std::async
异常是可能的,但后者如何在不知道异常类型的情况下存储它?异常不是从某个基类派生的(在这种情况下,可能可以通过某些Base::clone
“克隆”它),但可以是任何异常。我们能以某种方式神奇地“推断”异常类型吗?
总结一下,我的问题是:
如何在对象内部存储任意异常,然后在以后重新抛出它,而不知道异常类型?
答案 0 :(得分:4)
std::async
可以在std::thread
和std::packaged_task
之上实施。
std::packaged_task
可以(部分)在std::exception_ptr
和相关函数之上实现(除了线程退出就绪函数)。
std::exception_ptr
和相关函数不能用C ++编写。
答案 1 :(得分:3)
我不确定这是否能完全回答您的问题,但此示例可能会有所帮助。
我编译了以下内容:
int main()
{
throw 1;
}
使用命令
g++ -fdump-tree-gimple -std=c++11 main.cpp -o main
gimple(gcc&#39; s中间输出)是:
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
,这是整数的mangled类型。
编译时不可用的类型
类型符号只需在运行时可用。在一个试图隐藏尽可能多的符号的动态库中,它需要确保没有任何内部捕获和处理的异常可用。有关详细信息,请参阅https://gcc.gnu.org/wiki/Visibility,尤其是Problems with C++ exceptions (please read!)
部分。
有趣的是,在使用具有不同命名方案的不同编译器编译的动态库之间如何工作。