我可以复制构造带有错误信息的boost::exception吗?

Can I copy-construct a boost::exception with the error info?

提问人:sbi 提问时间:4/16/2015 最后编辑:sbi 更新时间:4/20/2015 访问量:762

问:

请考虑以下使用 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_implstd::exceptionExc


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

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_infoexception_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";
    }

这确实表明,当我将对象复制到基类对象中时,信息会丢失:Excexception_impl

========================================================================
exc:
Throw location unknown (consider using BOOST_THROW_EXCEPTION)
Dynamic exception type: some_exception
[tag_test_int*] = 42
========================================================================
*this:
Throw location unknown (consider using BOOST_THROW_EXCEPTION)
Dynamic exception type: exception_impl
std::exception::what: "blah"

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

我做错了什么?

C++ 异常 boost-exception

评论

0赞 sehe 4/16/2015
也许与 open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2106.htmlopen-std.org/jtc1/sc22/wg21/docs/papers/2007/n2179.html 有关
2赞 sbi 4/16/2015
好的,所以出于某种莫名其妙的原因(无论如何对我来说是莫名其妙的),当我以非虚拟方式从 .我很困惑,很想听听解释。exceptionboost::exception
0赞 sbi 4/16/2015
@sehe:我浏览了文件,但没有看到任何相关内容。你在暗示什么?
0赞 sehe 4/16/2015
看起来克隆显然不是一个功能,并解释了原因(例如“由于克隆功能只是 0x 之前的权宜之计”[...]“不 - 但例外(仅)将获得一个特殊的内置克隆机制 (n2179)”,暗示它以其他方式解决。再读一遍,看起来可能参与其中(另见 Luc 的回答boost::copy_exception)
3赞 Barry 4/20/2015
你能提供MCVE吗?这个问题很难理解。

答:

3赞 WaeCo 4/20/2015 #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未设置喷射。

评论

0赞 sbi 4/27/2015
所以我回家了,但时间到了。因此,我没有浪费一半的赏金,而是把它交给了这个答案,因为这是我唯一得到的。当我有时间工作时,我会去看看代码,并尝试弄清楚我的代码与你的代码有何不同。感谢你和其他所有调查过这个问题的人!
0赞 sbi 5/13/2015
我终于花时间去寻找这个。此代码在 coliru 上按预期工作,但在我的平台上不起作用。我不禁假设这是因为我们被困在 boost 1.52 上,据说它有一个错误。(我们也在使用较旧的编译器,但我怀疑这会导致这样的错误。由于我们无能为力,因此我们暂时只能以非虚拟方式推导。再次感谢您的努力!
0赞 Sven 5/13/2015
我的开发系统上有 boost 1.48,它的工作方式与 cliru 类似。所以也许你必须看看你的编译器,我的是 gcc 版本 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)。