【问题标题】:Can I copy-construct a boost::exception with the error info?我可以复制构造带有错误信息的 boost::exception 吗?
【发布时间】:2015-06-22 18:55:39
【问题描述】:

考虑以下使用 boost 异常类的代码:

class exception : virtual public boost::exception {
    // ...
};

template<typename Exc>
class exception_impl : virtual public std::exception
                     , public Exc {
public:
    exception_impl(const Exc& exc) : Exc(exc) {}
    virtual const char* what() const throw() {return "blah";}
};

(实际上这段代码更复杂。例如,exception_impl 仅派生自 std::exception,如果后者还不是 Exc 的直接或间接基类。但这只是分散了我对问题的注意力有,所以我跳过了。)


鉴于此,我现在可以派生我自己的异常类:

class some_exception : public exception {
    // ...
};

并使用它们:

struct tag_test_int;
typedef boost::error_info<tag_test_int,int> test_int_info;

void f()
{
    boost::throw_exception( exception_impl<some_exception>() << test_int_info(42) );
}

但是,结果表明生成的异常没有test_int_info 对象。所以我更改了exception_impl 构造函数以提供一些诊断信息:

    exception_impl(const Exc& exc)
    : Exc(exc) {
        std::cerr << "========================================================================\nexc:\n";
        std::cerr << boost::diagnostic_information(exc);
        std::cerr << "========================================================================\n*this:\n";
        std::cerr << boost::diagnostic_information(*this);
        std::cerr << "========================================================================\n";
    }

这确实表明当我将Exc 对象复制到exception_impl 基类对象中时信息丢失了:

==================================================== ======================= 除: 抛出位置未知(考虑使用 BOOST_THROW_EXCEPTION) 动态异常类型:some_exception [tag_test_int*] = 42 ==================================================== ======================= *这: 抛出位置未知(考虑使用 BOOST_THROW_EXCEPTION) 动态异常类型:exception_impl 标准::异常::什么:“废话”

IIRC,异常对象必须根据标准是可复制的,并且忽略可能的优化,将复制 throw 表达式的结果。所以 boost 的异常必须是可复制的,并且它们当然不会在此过程中丢失信息。我必须在这里遗漏一些相当明显的东西。

我做错了什么?

【问题讨论】:

  • 好的,所以由于一些莫名其妙的原因(无论如何我都莫名其妙),当我导出 exception 非虚拟时问题就消失了来自boost::exception。我很困惑,很想听听解释。
  • @sehe:我浏览了这些文件,但没有看到任何相关内容。你在暗示什么?
  • 看起来克隆显然不是一项功能,并说明原因(例如“由于克隆功能只是 0x 之前的权宜之计”[...]“否 - 但异常(仅)将获得特殊的内置克隆机制 (n2179)”here) 暗示它已通过其他方式解决。再读一遍,看起来boost::copy_exception 可能参与其中(另见Luc's answer
  • 你能提供一个 MCVE 吗?这个问题很难理解。

标签: c++ exception boost boost-exception


【解决方案1】:

对我来说非常好用:
(我不得不为 exception_impl 添加一个默认构造函数)

#include <iostream>
#include <exception>
#include <boost/exception/all.hpp>

using std::cout;

class myException : public virtual boost::exception {

};

template <class T>
class exception_impl : public virtual std::exception, public T {
public:
    exception_impl() {}
    exception_impl(const T& ex) : T(ex) {}
    virtual const char* what() const throw() {return "blah";}
};

class some_exception : public myException {

};

struct tag_test_int;
typedef boost::error_info<tag_test_int,int> test_int_info;

void f()
{
    boost::throw_exception( exception_impl<some_exception>() << test_int_info(42) );
}

int main() {

    try {
        f();
    } catch (boost::exception& e) {
        cout << boost::diagnostic_information(e);
    }

    return 0;
}

输出:

Throw location unknown (consider using BOOST_THROW_EXCEPTION)
Dynamic exception type: N5boost16exception_detail10clone_implI14exception_implI14some_exceptionEEE
std::exception::what: blah
[P12tag_test_int] = 42

编译使用:

  • g++ (Ubuntu 4.9.2-0ubuntu1~14.04) 4.9.2
  • 提升 1.55

我认为问题在于您在构造函数中输出诊断信息,而 tag_test_int 未设置 jet。

【讨论】:

  • 所以我回家了,但时间到了。因此,我没有浪费一半的赏金,而是把它交给了这个答案,因为这是我得到的唯一一个。当我找到工作时间时,我会去查看代码,并尝试找出我的代码与您的代码有何不同。感谢您和其他所有对此进行调查的人!
  • 我终于抽出时间来追查这个问题。 This code 在 coliru 上按预期工作,但在我的平台上不起作用。我不禁假设这是因为我们被 boost 1.52 卡住了,据说它有一个错误。 (我们也在使用一个较旧的编译器,但我怀疑这会导致这样的错误。)由于我们无能为力,我们暂时只能非虚拟地推导。 再次感谢您的努力!
  • 我的开发系统上有 boost 1.48,它就像在 cliru 上一样工作。所以也许你必须看看你的编译器,我的是 gcc 版本 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-07-01
  • 2013-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-25
  • 2016-05-11
相关资源
最近更新 更多