将标准::exception_ptr转换为提升::exception_ptr

Converting std::exception_ptr to boost::exception_ptr

本文关键字:ptr exception 转换 标准      更新时间:2023-10-16

我想使用期望boost::exception_ptr boost::promise::set_exception()。问题是,只有当我用enable_current_exception包裹我所有的投掷时,boost:exception_ptr似乎才能正常工作,我想避免这种情况。(无论如何,我都无法为第三方库执行此操作。我在整个代码中使用std::exception_ptr/std::current_exception,因此我正在寻找一种方法来传递std::exception_ptr需要boost:exception_ptr的地方。执行以下操作但编译的内容:

boost::exception_ptr convert(std::exception_ptr ex) {
    try {
        std::rethrow_exception(ex);
    }
    catch(auto& ex) {
        try {
            throw boost::enable_current_exception(ex);
        }
        catch (...) {
            return boost::current_exception();
        }
    }
}

你知道怎么做吗?

上下文:

我需要boost::future::then(),所以不幸的是,使用std::promise不是一种选择(至少目前)

如果您知道一种方法可以使boost::exception_ptr依赖于 gcc 4.8 编译器支持而不是enable_current_exception那也是一个可接受的解决方案。

不幸的是,我认为这是不可能的。但是,我可以为您提供三种可能的解决方案,按便利性排序:

1. 抓住一个标准::异常

boost::exception_ptr convert(std::exception_ptr ex)
{
    try {
        std::rethrow_exception(ex);
    } catch (const std::exception& e) {
        try {
            throw boost::enable_current_exception(e);
        } catch (...) {
            return boost::current_exception();
        }
    } catch (...) {
        try {
            throw boost::enable_current_exception(std::runtime_error("Unknown exception."));
        } catch (...) {
            return boost::current_exception();
        }
    }
}
int main()
{
    std::exception_ptr sep;
    try {
        throw std::runtime_error("hello world");
    } catch (...) {
        sep = std::current_exception();
    }
    boost::exception_ptr bep = convert(sep);
    try {
        boost::rethrow_exception(bep);
    } catch (const std::exception& e) {
        std::cout << e.what() << std::endl;
    }
}

这将打印"std::exception"而不是"hello world",因为来自派生类(在本例中为std::runtime_error)的信息将被切掉。

2. 直接扔标准::exception_ptr

boost::exception_ptr convert(std::exception_ptr ex)
{
    try {
        throw boost::enable_current_exception(ex);
    } catch (...) {
        return boost::current_exception();
    }
}
int main()
{
    std::exception_ptr sep;
    try {
        throw std::runtime_error("hello world");
    } catch (...) {
        sep = std::current_exception();
    }
    boost::exception_ptr bep = convert(sep);
    try {
        boost::rethrow_exception(bep);
    } catch (const std::exception_ptr& ep) {
        try {
            std::rethrow_exception(ep);
        } catch (const std::exception& e) {
            std::cout << e.what() << std::endl;
        }
    }
}

这个版本打印"hello world",尽管代价是额外的try/catch块。如果错误处理是在中心位置完成的,可能会显示一个对话框,我会选择这个解决方案。直到 boost 作者添加一个从 std::exception_ptrboost::exception_ptr 的构造函数,恐怕这已经足够好了。

使用 boost:

:p ackaged_task 而不是 boost::p romise

如果您可以忍受使用 packaged_task ,此解决方案有效:

#define BOOST_THREAD_VERSION 4
#include <boost/thread.hpp>
int main()
{
    boost::packaged_task<int()> pt([] () -> int {
        throw std::runtime_error("hello world");
    });
    boost::future<int> f1 = pt.get_future();
    boost::future<int> f2 = f1.then([] (boost::future<int> f) {
        return f.get() + 1;
    });
    boost::thread(std::move(pt)).detach();
    try {
        int res = f2.get();
    } catch (const std::runtime_error& e) {
        std::cout << e.what() << std::endl;
    }
}

打印"hello world"并允许您使用fut.then()

我发现不是最好的解决方案,但它有效。

  1. 克里特岛模板专业化。
namespace boost::exception_detail
{
template<>
class clone_impl< std::exception_ptr > : public clone_base
{
   std::exception_ptr mExceptionPtr;
public:
   clone_impl( std::exception_ptr exception_ptr )
      : mExceptionPtr{ std::move( exception_ptr ) }
   {
   }
   clone_base const* clone() const
   {
      return new clone_impl( *this );
   }
   void rethrow() const
   {
      std::rethrow_exception( mExceptionPtr );
   }
};
int clone_current_exception_non_intrusive( clone_base const*& cloned )
{
   cloned = new clone_impl< std::exception_ptr >{ std::current_exception() };
   return clone_current_exception_result::success;
}
} 
  1. 添加BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR定义