如果 std::async 调用的函数抛出异常,那么这个异常会被存储在值的位置,同时 future 变为 ready ,如果调用 get() 会重新抛出存储的异常。
Note:
标准并没有指定原来的异常对象是被重新抛出或者拷贝后抛出,不同的编译器会做不同的选择。
对于 std::packaged_task<> 包装的函数如果抛出异常,那么处理与 std::async 一致。 std::promise<> 提供类似的机制,如果期望存储一个异常那么在 std::promise<> 对象上就需要使用 set_exception() 代替 set_value() 。
保存一个异常到 future 中的另外一个方式是在没有调用 std::promise<> 的 set_xxxx 函数或者被 std::packaged_task<> 包装的任务的情况下就销毁与 future 关联的 std::promise<> 和 std::packaged_task<>。无论哪种情况,析构函数都会存储一个错误码是 std::future_errc::broken_promise 的 std::future_error 异常,表示关联的 future 并没有 ready 。
#include <iostream>
#include <future>
int main() {
// std::async
std::future<void> result1 = std::async([] {
throw std::runtime_error("runtime error.");
});
try {
result1.get();
} catch (const std::runtime_error &e) {
std::cout << "Async exception: " << e.what() << std::endl;
}
std::promise<int> promise;
try {
// 正常的情况就set_value
// promise.set_value(66);
// 主动抛出一个异常进行测试
throw std::out_of_range("the value out of range.");
} catch (...) {
// 使用std::current_exception 存储被抛出的异常;
// 可以使用 std::copy_exception 存储没有被抛出的异常;
promise.set_exception(std::current_exception());
}
try {
promise.get_future().get();
} catch (const std::out_of_range &e) {
std::cout << "Promise exception: " << e.what() << std::endl;
}
// 存储异常的其他方式,
// 在没有调用 std::promise的set_xxx函数
// 或者没有调用被 std::packaged_task 包装的任务情况下
// 就销毁与 future关联的 std::promise,std::packaged_task 对象
// std::packaged_task<>
std::future<void> future;
try {
// 提前销毁task
{
std::packaged_task<void()> task([] {
std::cout << "do packaged task." << std::endl;
});
future = task.get_future();
}
future.get();
}
catch (const std::future_error &e) {
std::cout << "Packaged task exception: " << e.what() << std::endl;
}
// std::promise<>
try {
// 提前销毁promise
{
std::promise<void> promise;
future = promise.get_future();
}
future.get();
}
catch (const std::future_error &e) {
std::cout << "Promise exception: " << e.what() << std::endl;
}
return 0;
}
更多内容:https://blog.nas-kk.top/?p=106