C++ 带有std::Error\u代码的错误堆栈

C++ 带有std::Error\u代码的错误堆栈,c++,c++11,error-handling,C++,C++11,Error Handling,对于错误处理,异常对我来说是有问题的,因为我的代码将是一个动态链接的库。此外,我认为例外情况只应在例外情况下使用。但我会有一些情况下,错误可能会发生,这不是例外。另一个问题是我的库将从C#调用。因此,对所有错误使用异常似乎不是正确的选择 但是我发现std::error_代码和std::error_类别的概念非常令人愉快,我希望在我的应用程序中使用它。但是,我还想为错误提供某种堆栈跟踪 举个例子: 用户希望从数据库加载域对象。要加载此域对象,应用程序需要加载不同表中的行。假设找不到所需的行之一。在

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

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

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

我考虑从std::error_代码派生,并使用指向底层std::error_代码的指针和获取所有这些底层对象的方法来扩展该类。然而,我不确定这种技术是否是一个好主意,因为我读到在设计std::error_代码以提高效率时非常小心

我们希望error_代码是一种无需切片和堆分配即可复制的值类型,但我们也希望它具有基于错误类别的多态行为

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

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

编辑3
我没有想到不可能有一个本身包含boost::optional的类。所以现在我看不到在堆上没有分配的情况下我想要什么的可能性。

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


class my\u error:public std::error\u code
{
公众:
my_error():std::error_code(),m_innerror(NULL){};
my_error(int val,const std::error_category&cat):std::error_code(val,cat),m_innerror(NULL){};
我的错误(std::error\u code&error):std::error\u code(error),m\u innerror(NULL){};
my_error(const std::error_code&error):std::error_code(error),m_innerror(NULL){};
~my_error()
{
删除m_innerError;
}
模板
我的错误(ErrorCodeEnum e,
typename boost::enable_如果::type*=0)
{
*这=制造自定义错误(e);
}
模板
typename boost::enable_if::type&
运算符=(ErrorCodeEnum val)
{
*这=生成自定义错误(val);
归还*这个;
}
我的错误常量*获取内部()常量
{
返回m_innerror;
};
无效包装(const my_错误和错误)
{
m_innerError=新的我的错误(错误);
};
私人:
我的错误*我的错误;
};

为什么不使用
internal\u exception()
方法定义自己的
std::exception
派生异常类来返回内部异常(源自较低级别)?您的UI甚至可能捕捉到
业务异常
,但在
内部异常()中导航
您可以记录每一层中发生的所有事情(如果您想这样做,可能出于安全原因,不公开底层细节)哦,顺便说一句,IMO
std::error\u code
std::error\u category
的概念不适合您的场景。应用程序应该使用异常来通知错误,错误代码是非C++环境的遗产(例如操作系统API或设备驱动程序)。在这种情况下,您应该创建一个包装器,用
std::error_code
封装函数的错误代码;使用C++ish接口公开它们,然后使用异常管理应用程序中的错误(使用
error\u 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;
};