繁体   English   中英

与std :: error_code的错误堆栈

[英]Error stack with std::error_code

对于错误处理,异常对我来说是有问题的,因为我的代码将是一个动态链接的库。 此外,我认为例外情况只应在特殊情况下使用。 但是我会遇到可能发生错误但不例外的情况。 另一个问题是我的库将从C#调用。 因此,对所有错误使用异常似乎不是正确的选择。

但我发现std :: error_code和std :: error_category的概念非常令人愉快,并希望在我的应用程序中使用它。 但是,我还想为错误提供某种堆栈跟踪。

考虑一个示例:用户想要从数据库加载域对象。 要加载此域对象,应用程序需要从不同的表加载行。 假设找不到其中一个必需的行。 在这种情况下,数据库层将生成一些“未找到”错误。 如果我的所有传播这个错误直到用户因为没有人知道发生什么没有发现该错误信息不会是非常有益的。 同样,如果每个层处理较低层的错误并生成相应的新错误,抽象出低级错误,我最终会得到类似“无法从数据库加载”这样的东西,这也不是很有用。 我想要的是两者兼而有之。 也就是说,每个层都抽象出从任何较低级别获得的错误,以便能够向最终用户显示描述性消息,但同时我不想丢失有关低级别错误的信息。 所以我希望有类似错误堆栈跟踪的东西。

我考虑从std :: error_code派生并使用指向底层std :: error_code的方法扩展该类,并使用方法来获取所有这些底层对象。 但是,我不确定这种技术是不是一个好主意,因为我读到在设计std :: error_code以使其高效时需要小心。

我们希望error_code是一个值类型,可以在不进行切片的情况下进行复制,也不需要堆分配,但我们也希望它具有基于错误类别的多态行为。

编辑我现在认为这种技术也会引入切片问题,不是吗?

编辑2我现在想通过从std :: error_code派生来实现它。 而不是指针,什么需要在某处进行堆分配,我的派生类将有一个boost :: optional。 这样,只需复制内部错误代码就可以在堆栈上创建内部错误代码。 一个不存在的内部错误代码可以正确地由boost :: optional表示。 切片仍然是一个问题,但我想这是可以忽略的,因为将我的派生类的实例分配给std :: error_code变量的情况不是必要的,即使它发生了,我也只会丢失有关内部错误代码的信息。 此外,我可以提供从std :: error_code到我没有内部错误代码的派生类的转换。

编辑3我没想到让一个包含boost :: optional本身的类是不可能的。 所以现在我没有看到没有在堆上分配我想要的东西的任何可能性。

最后我是从std::error_code派生的。 我的派生类有一个成员,它是指向同一个类的实例的指针。 我向该类添加了一个wrap()方法,该方法接受与该参数相同的类的实例,并在堆上分配它的副本。 派生类的析构函数确保再次释放内存。 我也为这个内部错误代码添加了一个getter方法。 这样我可以堆叠几个错误代码。 缺点是,我需要堆分配,但我只是希望,在我的场景中,这不会导致重大的性能问题。 我的类还提供了从std::error_code转换。


class my_error : public std::error_code
{
public:
    my_error() : std::error_code(), m_innerError(NULL) {};
    my_error( int val, const std::error_category & cat ) : std::error_code(val, cat), m_innerError(NULL) {};
    my_error( std::error_code & error ) : std::error_code(error), m_innerError(NULL) {};
    my_error( const std::error_code & error ) : std::error_code(error), m_innerError(NULL) {};
    ~my_error()
    {
        delete m_innerError;
    }

    template <class ErrorCodeEnum>
    my_error(ErrorCodeEnum e,
                   typename boost::enable_if<std::is_error_code_enum<ErrorCodeEnum> >::type* = 0)
    {
        *this = make_custom_error(e);
    }

    template<typename ErrorCodeEnum>
    typename boost::enable_if<std::is_error_code_enum<ErrorCodeEnum>, error_code>::type &
    operator=( ErrorCodeEnum val )
    {
        *this = make_custom_error(val);
        return *this;
    }

    my_error const * get_inner() const
    {
        return m_innerError;
    };

    void wrap( const my_error & error)
    {
        m_innerError = new my_error(error);
    };

private:
    my_error * m_innerError;
};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM