如何正确使用BOOST_THROW_EXCEPTION?

How to use BOOST_THROW_EXCEPTION correctly?

我尝试使用 boost 异常并失败。 有问题代码:

struct exception_base : virtual std::exception, virtual boost::exception 
{
    exception_base(std::exception&& e)
        : std::exception(e)
    {}
};

int main()
{
    std::string exception_description;

    try
    {
        BOOST_THROW_EXCEPTION(exception_base(std::runtime_error("hello exception")));
    }
    catch (exception_base& ex)
    {
        exception_description = boost::diagnostic_information(ex);
    }

    return 0;
}

在这种情况下,exception_description 的值具有最后一个字符串 - “std::exception::what: Unknown exception”。这是意想不到的价值。如果我将 BOOST_THROW_EXCEPTION 更改为通常的抛出 - exception_description 值的最后一个字符串看起来符合预期 - “std::exception::what: hello exception

那么如何正确使用BOOST_THROW_EXCEPTION呢?

您的自定义异常 class 不是必需的,它是您出现问题的根本原因。如果你删除它,你可以这样做:

BOOST_THROW_EXCEPTION(std::runtime_error("hello exception"));

然后:

catch (const std::exception& ex)

并且代码将按您期望的方式工作。

为什么以前没有用?好吧,您的 exception_base class 没有存储错误消息,因此当您从 std::exception 构建它时,它无法存储消息(例如来自原始 runtime_error)。

你可以用很多不同的方法来修复它,但最终它们会归结为同一件事:如果你想让你的自定义异常 class 包含一个消息字符串,它必须以某种方式包含该消息字符串.

我喜欢在 95% 的情况下不定义自定义异常类型,所以我建议您保持简单并使用 runtime_error (and/or logic_error).

请注意,BOOST_THROW_EXCEPTION 会自动添加 boost::exception 作为抛出类型的基础 class,因此您无论如何都不需要自己这样做——没有任何优势。


其他:

  • 在您的 catch 站点使用 std::cerr << boost::diagnostic_information(ex) << std::endl;,这将打印 BOOST_THROW_EXCEPTION 添加的所有元数据,例如:文件、行、函数等
  • 如果你在 BOOST_THROW_EXCEPTION() 中放置一个 std::exception 你可以用 boost::enable_error_info() 包装你的 std::exception 来改变类型为 boost::exception 然后允许您通过 operator<<
  • 使用其他任意字段丰富异常