C ++中的自定义异常 [英] Custom Exceptions in C++

查看:104
本文介绍了C ++中的自定义异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试为我正在开发的C ++库制作一些自定义异常类。这些自定义异常捕获调试所需的额外信息,例如文件,行号等,如果由于某种原因,测试异常没有被捕获在正确的地方。但是大多数人似乎建议从STL中继承std :: exception类,我同意,但我想知道也许最好使用多继承继承每个衍生的std :: exception类(例如。std :: runtime_error)和自定义异常类,如下面的代码?

I've been trying to make some custom exception classes for a C++ library I'm working on. These custom exceptions capture extra info, such as file,line number,etc, needed for debugging, if for some reason while testing an exception is not caught in the right place. However most people seem to recommend inheriting from the std::exception class in the STL, which I agree with, but I was wondering maybe it would be better to use multiple inheritance to inherit from each of the derived std::exception classes (eg. std::runtime_error) and a custom exception class, as in the code below?

另一件事,如何在异常类中复制构造函数和赋值运算符?

Another thing, how does one go about copy constructors and assignment operators in exception classes? Should they be disabled?

class Exception{
    public:
        explicit Exception(const char *origin, const char *file, 
                           const int line, const char *reason="", 
                           const int errno=0) throw();

    	virtual ~Exception() throw();

    	virtual const char* PrintException(void) throw();

    	virtual int GetErrno(void);

    protected:
    	std::string m_origin;
    	std::string m_file;
    	int m_line;
    	std::string m_reason;
    	int m_errno;
}; 

class RuntimeError: public virtual std::runtime_error, public Exception{
    public:
              explicit RuntimeError(const char *origin, const char *file, 
                                    const int line, const char *reason="", 
                                    const int errno=0) throw();
    	virtual ~RuntimeError() throw();
};


推荐答案


最好使用多重继承继承每个派生的std :: exception类

I was wondering maybe it would be better to use multiple inheritance to inherit from each of the derived std::exception classes

注意这是一个问题,由于标准库中的异常非虚拟地从彼此导出的事实。如果你引入多重继承,你会得到没有虚拟继承的可怕的钻石异常层次,并且不能捕获 std :: exception& 的派生异常,因为你的派生异常类包含 std :: exception 的两个子对象,使 std :: exception 是一个歧义基类。

Note that this is a problem, due to the fact that the exceptions in the standard library derive non-virtually from each other. If you introduce multiple inheritance, you get the dreaded diamond exception hierarchy without virtual inheritance and won't be able to catch derived exceptions by std::exception&, since your derived exception class carries two subobjects of std::exception, making std::exception an "ambiguous base class".

具体示例:

class my_exception : virtual public std::exception {
  // ...
};

class my_runtime_error : virtual public my_exception
                       , virtual public std::runtime_error {
  // ...
};

现在 my_runtime_error code> std :: exception 两次,一次通过 std :: run_time_error ,一次通过 my_exception 。由于前者实际上不是从 std :: exception 派生的,因此

Now my_runtime_error derives (indirectly) from std::exception twice, once through std::run_time_error and once through my_exception. Since the former doesn't derive from std::exception virtually, this

try {
  throw my_runtime_error(/*...*/);
} catch( const std::exception& x) {
  // ...
}

将无法工作。

编辑:

我想我见过第一个例子在Stroustrup的一本书中涉及MI的异常类层次结构,所以我总结说,一般来说,这是一个好主意。 std lib的异常不会从对方派生出来,我认为是一个失败。

I think I've seen the first example of an exceptions class hierarchy involving MI in one of Stroustrup's books, so I concluded that, in general, it is a good idea. That the std lib's exceptions do not derive virtually from each other I consider as a failure.

当我最后设计一个异常层次结构时,我非常广泛地使用了MI,但并没有从std lib的异常类派生。在该层次结构中,存在抽象异常类,您可以定义这些异常类,以便用户可以捕获它们,以及从这些抽象类和实现基类派生的相应实现类。为了使这更容易,我定义了一些模板,这将做所有的辛勤工作:

When I last designed an exception hierarchy, I used MI very extensively, but did not derive from the std lib's exception classes. In that hierarchy, there were abstract exception classes which you defined so your users could catch them, and corresponding implementation classes, derived from these abstract classes and from an implementation base class, which you would actually throw. To make this easier, I defined some templates which would do all the hard work:

// something.h
class some_class {
private:
  DEFINE_TAG(my_error1); // these basically define empty structs that are needed to 
  DEFINE_TAG(my_error2); // distinguish otherwise identical instances of the exception 
  DEFINE_TAG(my_error3); // templates from each other (see below)
public:
  typedef exc_interface<my_error1>  exc_my_error1;
  typedef exc_interface<my_error2>  exc_my_error2;
  typedef exc_interface<my_error3,my_error2> // derives from the latter
                                    exc_my_error3;

  some_class(int i);
  // ...
};

//something.cpp
namespace {
  typedef exc_impl<exc_my_error1> exc_impl_my_error1;
  typedef exc_impl<exc_my_error2> exc_impl_my_error2;
  typedef exc_impl<exc_my_error3> exc_impl_my_error3;
  typedef exc_impl<exc_my_error1,exc_my_error2> // implements both
                                  exc_impl_my_error12;
}
some_class::some_class(int i)
{
  if(i < 0) 
    throw exc_impl_my_error3( EXC_INFO  // passes '__FILE__', '__LINE__' etc.
                            , /* ... */ // more info on error
                            ); 
}

现在回想起来,我想我可以把 exc_impl 类模板派生自 std :: exception (或std lib例外层次结构中的任何其他类,作为可选模板参数传递) ,因为它从未从任何其他 exc_impl 实例派生。但是当时这是不需要的,所以它从来没有发生在我身上。

Looking back at this now, I think I could have made that exc_impl class template derive from std::exception (or any other class in the std lib exception hierarchy, passed as optional template parameter), since it never derives from any other exc_impl instance. But back then this wasn't needed, so it never occurred to me.

这篇关于C ++中的自定义异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆