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

标签 c++

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

  • 异常链:我想实现“异常翻译”的概念,当在更高级别捕获的异常包装和“翻译”较低级别的异常时,还以某种方式保留这些情人级别的异常(在 InnerException 成员中,在这个案例)。为此,应该有一些机制来存储内部异常以及在上层抛出的每个异常。 InnerException成员在下面的实现中提供了这一点。
  • 异常继承:应该可以派生IoException来自 Exception , 和 SerialPortException来自 IoException , 例如。虽然这看起来微不足道,但应该能够动态识别捕获异常的类型(例如用于日志记录或向用户显示),最好没有 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);
    }
    

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

    Exception chain formatting

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

    小记: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;
    };
    

    现在我们这里有什么。复制构造函数和赋值运算符 protected以防止复制。每个对象都将“拥有”其内部异常对象(并在析构函数中将其删除),因此默认的浅拷贝将是 Not Acceptable 。然后我们有两个看起来很标准的构造函数和删除 InnerException 的虚拟析构函数。目的。 Clone()虚方法负责对对象进行深度复制,主要用于存储内部异常对象(参见第二个构造函数)。最后 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;
        }
    };
    

    我不喜欢我必须提供的事实 protected每次都复制构造函数和赋值运算符,我不喜欢我必须克隆 Clone 的事实。每次使用方法,甚至复制复制基本成员的代码(InnerException ...),只是...我认为这不是优雅的解决方案。但我想不出更好的方法。您对如何“正确”实现这个概念有什么想法吗?或者这可能是 C++ 中这个概念的最佳实现?或者也许我这样做完全错误?

    P.S.:我知道 C++11(也在 Boost 中)存在一些用于此目的的机制(异常链)和一些新的异常类,但我主要对自定义的“旧 C++ 兼容”方式感兴趣。但是,此外,如果有人可以提供 C++11 中的任何代码来完成相同的工作,那就太好了。

    最佳答案

    C++11 已经有了 nested_exception .在 Boostcon/C++Next 2012 上讨论了 C++03 和 C++11 中的异常。视频在 youtube 上:

  • http://www.youtube.com/watch?v=N9bR0ztmmEQ&feature=plcp
  • http://www.youtube.com/watch?v=UiZfODgB-Oc&feature=plcp
  • 关于c++ - 实现 C++ 异常链的正确/优雅方式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13357178/

    相关文章:

    C++ 调用类成员变量 "attributes"是否正确?

    c++ - Q_REQUIRED_RESULT 做什么?

    c++ - 无法进行嵌套循环

    c++ - 虚拟继承不会破坏静态组合?

    用于 TCP 套接字的基于 C++ 流的 JSON 解析器

    c++ - 向电子邮件服务器发送 STARTTLS 命令后必须发送哪些数据

    c++ - 您如何抽象要在屏幕上显示的信息?

    c++ - 在类中初始化静态结构 tm

    c++ - exif和xmp有什么关系?它们可以互换吗?

    c++ - 如何使 GCC 将 'arg,##__VA_ARGS__' 减少到 'arg' 以将其用作单个宏参数?