捕获 Diamond Of Death 异常(boost::system::system_error 和 std::system_error)

Catching a Diamond Of Death Exception (boost::system::system_error and std::system_error)

提问人:SumDood 提问时间:10/24/2023 最后编辑:SumDood 更新时间:10/27/2023 访问量:99

问:

我有一个库,我希望利用 boost::system::system_error 的设计。C++ 在 2011 年通过 std::system_error 采用了这种设计。我希望客户端代码可以选择使用 Boost 异常或标准异常。因此,当我的库代码需要传达错误时,我会抛出我自己的异常类型,该异常类型继承自 boost::system::system_errorstd::system_error

class my_exception : public std::system_error, public boost::system::system_error {
  // implementation
};

不幸的是,这是一颗致命的死亡钻石,相对于共同的基类。尽管如此,客户端代码还是能够将这些异常捕获为以下 or :std::runtime_errorstd::system_errorboost::system::system_error

try {
  a_function_that_might_throw_my_exception();
} catch (const std::system_error& ex) {
  // Works as intended - correctly catches a reference to the `my_exception` object
}

try {
  a_function_that_might_throw_my_exception();
} catch (const boost::system::system_error& ex) {
  // Also works
}

但是,由于菱形的模糊性,类型的表达式不能绑定到对(或其基类)的引用:它应该绑定到的基类对象,还是应该绑定到的基类对象?结果是抛出的物体根本没有被捕获:my_exceptionstd::runtime_errorstd::exceptionstd::system_errorboost::system::system_error

try {
  a_function_that_might_throw_my_exception();
} catch (const std::runtime_error& ex) {
  // Doesn't catch here!
} catch (...) {
  std::printf("Sadness\n");
}

Godbolt 演示

主要问题:有没有办法与编译器沟通,在将致命的菱形类型绑定到基的引用时,应该首选哪个基类子对象?在普通代码中,你可以 或 ,但我不能将 a 写入编译器神奇的异常处理代码中。static_cast<const std::runtime_error&>(ex)static_cast<const boost::system::system_error&>(ex)static_cast

次要问题:有没有更好的方法可以使我的代码与两者和错误处理互操作?std::boost::system::

编辑: 问题在于,一些库代码在后台同时使用 API 和 API;因此,我不一定总是可以选择抛出我的选择或。boost::std::boost::system::system_errorstd::system_error

C++ C++11 异常 升压 系统

评论

4赞 Alan Birtles 10/24/2023
对我来说似乎是个坏主意,只需扔掉一个或另一个并记录下哪一个。您甚至可以使用编译器标志在它们之间切换
1赞 NathanOliver 10/24/2023
就我个人而言,我会将其作为编译时选项进行处理。有一个别名 like,然后有using exception_base = EXCEPTION_BASE_TO_USE#ifndef USE_BOOST_EXCEPTIONS #then #define EXCEPTION_BASE_TO_USE std::exception #else #define EXCEPTION_BASE_TO_USE boost::exception
0赞 HolyBlackCat 10/24/2023
您支持的目标是什么?我什至不会添加宏开关。任何理智的用户代码都已经抓住了两者,并且,如果在项目中使用了这部分提升,我认为?boost::system_errorstd::system_errorboost::system_error
0赞 SumDood 10/25/2023
我的想法是,虽然不是官方标准,但 Boost 的某些方面是事实上的标准(尤其是 Boost.ASIO 和 ASIO 所依赖的 Boost 的任何部分,包括 Boost.System)。必须处理两个并行且几乎相同的 API 进行错误处理是令人讨厌的 - 我有一种优雅的(ish)方法来允许客户端代码使用他们选择的 ;我试图为.error_codesystem_error
0赞 James Kanze 10/25/2023
我认为这是标准(和提升)的缺陷。异常层次结构中的所有继承都应该是 ,以避免这种问题(这在最初引入标准时非常频繁)。并不是说这对你有任何帮助。virtual

答: 暂无答案