简体   繁体   English

与std :: error_code的错误堆栈

[英]Error stack with std::error_code

For error handling, exceptions are problematic for me because my code is going to be a dynamically linked library. 对于错误处理,异常对我来说是有问题的,因为我的代码将是一个动态链接的库。 Furthermore I think exceptions should only be used in exceptional cases. 此外,我认为例外情况只应在特殊情况下使用。 But I will have cases where an error might occur that is not exceptional. 但是我会遇到可能发生错误但不例外的情况。 Another problem is that my library will be called from C#. 另一个问题是我的库将从C#调用。 So using exceptions for all errors does not seem the right choice here. 因此,对所有错误使用异常似乎不是正确的选择。

But I find the concept of std::error_code and std::error_category quite pleasant and would like to use it in my application. 但我发现std :: error_code和std :: error_category的概念非常令人愉快,并希望在我的应用程序中使用它。 However, I would also like to offer some kind of stack trace for errors. 但是,我还想为错误提供某种堆栈跟踪。

Consider an example: The user wants to load a domain object from a database. 考虑一个示例:用户想要从数据库加载域对象。 To load this domain object the application needs to load rows from different tables. 要加载此域对象,应用程序需要从不同的表加载行。 Suppose one of the required rows cannot be found. 假设找不到其中一个必需的行。 In this case the database layer would generate some "not found" error. 在这种情况下,数据库层将生成一些“未找到”错误。 If i propagate this error all up to the user the error message will not be very helpful because nobody knows what was not found. 如果我的所有传播这个错误直到用户因为没有人知道发生什么没有发现该错误信息不会是非常有益的。 Likewise, if each layer handles the errors of the lower layer and generates a corresponding new error, abstracting the low level error, I would end up with something like "unable to load from database" which again is not very helpful. 同样,如果每个层处理较低层的错误并生成相应的新错误,抽象出低级错误,我最终会得到类似“无法从数据库加载”这样的东西,这也不是很有用。 What I would like is to have both. 我想要的是两者兼而有之。 That is each layer abstracts errors it gets from any lower level to be able to display descriptive messages to the end user but at the same time I don't want to lose information about the low level error. 也就是说,每个层都抽象出从任何较低级别获得的错误,以便能够向最终用户显示描述性消息,但同时我不想丢失有关低级别错误的信息。 So I would like to have something like an error stack trace. 所以我希望有类似错误堆栈跟踪的东西。

I thought about deriving from std::error_code and extend the class with a pointer to an underlying std::error_code and methods to get all these underlying objects. 我考虑从std :: error_code派生并使用指向底层std :: error_code的方法扩展该类,并使用方法来获取所有这些底层对象。 However, I am not sure if this technique would be a good idea because I read that care was taken when designing std::error_code to make it efficient. 但是,我不确定这种技术是不是一个好主意,因为我读到在设计std :: error_code以使其高效时需要小心。

We want error_code to be a value type that can be copied without slicing and without requiring heap allocation, but we also want it to have polymorphic behavior based on the error category. 我们希望error_code是一个值类型,可以在不进行切片的情况下进行复制,也不需要堆分配,但我们也希望它具有基于错误类别的多态行为。

EDIT I now think this technique would also introduce slicing problems, wouldn't it? 编辑我现在认为这种技术也会引入切片问题,不是吗?

EDIT 2 I now think to implement it by deriving from std::error_code. 编辑2我现在想通过从std :: error_code派生来实现它。 Instead of a pointer, what would need heap allocation somewhere, my derived class would have a boost::optional. 而不是指针,什么需要在某处进行堆分配,我的派生类将有一个boost :: optional。 This way the inner error code could be created on the stack simply by copying it. 这样,只需复制内部错误代码就可以在堆栈上创建内部错误代码。 A non-existing inner error code could be represented by boost::optional correctly. 一个不存在的内部错误代码可以正确地由boost :: optional表示。 Slicing would still be a problem but I guess it is neglectable because the case of assigning an instance of my derived class to a std::error_code variable would not be necessary and even if it happens I would only loose information about the inner error codes. 切片仍然是一个问题,但我想这是可以忽略的,因为将我的派生类的实例分配给std :: error_code变量的情况不是必要的,即使它发生了,我也只会丢失有关内部错误代码的信息。 Furthermore I could provide a conversion from std::error_code to my derived class that has no inner error codes. 此外,我可以提供从std :: error_code到我没有内部错误代码的派生类的转换。

EDIT 3 I didn't think of that it is not possible to have a class containing a boost::optional of itself. 编辑3我没想到让一个包含boost :: optional本身的类是不可能的。 So right now I don't see any possibility for what I would like to have without an allocation on the heap. 所以现在我没有看到没有在堆上分配我想要的东西的任何可能性。

Finally I'm deriving from std::error_code . 最后我是从std::error_code派生的。 My derived class has a member that is a pointer to an instance of the same class. 我的派生类有一个成员,它是指向同一个类的实例的指针。 I added a wrap() method to that class that takes an instance of the same class as argument and allocates a copy of it on the heap. 我向该类添加了一个wrap()方法,该方法接受与该参数相同的类的实例,并在堆上分配它的副本。 The destructor of my derived class ensures that the memory is freed again. 派生类的析构函数确保再次释放内存。 I added a getter method for this inner error code as well. 我也为这个内部错误代码添加了一个getter方法。 This way i can stack several error codes. 这样我可以堆叠几个错误代码。 Drawback is, that I need heap allocation, but I simply hope, that in my scenario this will not cause significant performance issues. 缺点是,我需要堆分配,但我只是希望,在我的场景中,这不会导致重大的性能问题。 My class also provides conversion from std::error_code . 我的类还提供了从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