实现C++异常链的正确/优雅方式?

TX_*_*TX_ 13 c++

我想在C++中实现一个Exception类,它模仿.NET框架中的一个(并且Java也有类似的东西),用于以下目的:

  1. 异常链接:我想实现"异常转换"的概念,当在较高级别捕获的异常包装并"翻译"较低级别的异常时,也会以某种方式保留这些情人级异常(在此InnerException成员中,在此情况下) .为此,应该有一些机制来存储内部异常以及在上层抛出的每个异常.InnerException成员在下面的实现中提供了这个.

  2. 例外的继承:应该有可能获得IoExceptionException,并SerialPortExceptionIoException,例如.虽然这看起来微不足道,但应该能够动态识别捕获的异常类型(例如,用于记录目的,或显示给用户),最好没有RTTI的开销typeid.

这是我想要的示例异常处理逻辑:

try
{
    try
    {
        try
        {
            throw ThirdException(L"this should be ThirdException");
        }
        catch(Exception &ex)
        {
            throw SubException(L"this should be SubException", ex);
        }
    }
    catch(Exception &ex)
    {
        throw SubException(L"this should be SubException again", ex);
    }
}
catch(Exception &ex)
{
    throw Exception(L"and this should be Exception", ex);
}
Run Code Online (Sandbox Code Playgroud)

当在最上层中捕获"最外层"异常时,我希望能够通过InnerException成员解析和格式化整个异常链,以显示如下内容:

异常链格式化

到目前为止,我已经提出了以下实现:

小记:CString是特定于Microsoft的字符串类(仅适用于不熟悉Visual C++的人).

class Exception
{
protected:

    Exception(const Exception&) {};
    Exception& operator= (const Exception&) {};

public:

    Exception(const CString &message) : InnerException(0), Message(message) {}
    Exception(const CString &message, const Exception &innerException) : InnerException(innerException.Clone()), Message(message) {}

    virtual CString GetExceptionName() const { return L"Exception"; }

    virtual Exception *Clone() const
    {
        Exception *ex = new Exception(this->Message);
        ex->InnerException = this->InnerException ? this->InnerException->Clone() : 0;
        return ex;
    }

public:

    virtual ~Exception() { if (InnerException) delete InnerException; }

    CString Message;
    const Exception *InnerException;
};
Run Code Online (Sandbox Code Playgroud)

现在我们在这里有什么 复制构造函数和赋值运算符是protected为了防止复制.每个对象将"拥有"其内部异常对象(并在析构函数中将其删除),因此默认的浅层复制将是不可接受的.然后我们有两个非常标准的构造函数和虚拟析构函数来删除InnerException对象.Clone()virtual方法负责深度复制对象,主要用于存储内部异常对象(请参阅第二个构造函数).最后,GetExceptionName()虚方法提供了RTTI的廉价替代方法,用于识别异常类名称(我认为这看起来并不酷,但我无法提出更好的解决方案;相比之下:在.NET中可以简单地使用someException.GetType().Name).

现在这样做了.但是......出于某个特殊原因,我不喜欢这个解决方案:每个派生类所需的编码量.考虑我必须派生SubException类,它提供对基类功能的绝对零添加,它只提供自定义名称("SubException",可能是"IoException","ProjectException",...)以区分它的用法场景.我必须为每个这样的异常类提供几乎相同数量的代码.这里是:

class SubException : public Exception
{
protected:

    SubException(const SubException& source) : Exception(source) {};
    SubException& operator= (const SubException&) {};

public:

    SubException(const CString &message) : Exception(message) {};
    SubException(const CString &message, const Exception &innerException) : Exception(message, innerException) {};

    virtual CString GetExceptionName() const { return L"SubException"; }

    virtual Exception *Clone() const
    {
        SubException *ex = new SubException(this->Message);
        ex->InnerException = this->InnerException ? this->InnerException->Clone() : 0;
        return ex;
    }
};
Run Code Online (Sandbox Code Playgroud)

我不喜欢protected每次都要提供复制构造函数和赋值运算符的事实,我不喜欢Clone每次都必须克隆方法的事实,甚至复制复制基本成员的代码(InnerException... ),简单地......我不认为这是优雅的解决方案.但我无法想到更好的一个.您是否有任何想法如何"正确"实施这一概念?或者这可能是C++中这个概念的最佳实现?或者也许我这样做完全错了?

PS:我知道C++ 11(也在Boost中)存在一些用于此目的的机制(异常链接)和一些新的异常类,但我主要对定制的"旧C++兼容"方式感兴趣.但是,如果有人能够在C++ 11中提供完成相同的代码,那将是一件好事.

Jur*_*aho 16

C++ 11已经有了nested_exception.在Boostcon/C++ 2012年的C++ 03和C++ 11中有一个关于异常的讨论.视频在youtube上:

  1. http://www.youtube.com/watch?v=N9bR0ztmmEQ&feature=plcp
  2. http://www.youtube.com/watch?v=UiZfODgB-Oc&feature=plcp