[英]Custom Exceptions in C++
我一直在尝试为我正在研究的C ++库创建一些自定义异常类。 这些自定义异常捕获调试所需的额外信息,例如文件,行号等,如果出于某种原因,在测试异常时没有捕获到正确的位置。 然而,大多数人似乎建议继承STL中的std :: exception类,我同意这一点,但我想知道使用多重继承来继承每个派生的std :: exception类会更好(例如.std :: runtime_error)和自定义异常类,如下面的代码?
另外,如何在异常类中使用复制构造函数和赋值运算符? 他们应该被禁用吗?
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类会更好
请注意,这是一个问题,因为标准库中的异常非虚拟地相互派生。 如果你引入了多重继承,你就会得到没有虚拟继承的可怕钻石异常层次结构,并且无法通过std::exception&
捕获派生异常,因为你的派生异常类带有两个std::exception
子对象,使得std::exception
是一个“模糊的基类”。
具体例子:
class my_exception : virtual public std::exception {
// ...
};
class my_runtime_error : virtual public my_exception
, virtual public std::runtime_error {
// ...
};
现在my_runtime_error
两次从std::exception
派生(间接),一次通过std::run_time_error
,一次通过my_exception
。 由于前者不是虚拟地从std::exception
派生的,所以
try {
throw my_runtime_error(/*...*/);
} catch( const std::exception& x) {
// ...
}
不行。
编辑:
我想我已经在Stroustrup的一本书中看到了涉及MI的异常类层次结构的第一个例子,所以我得出结论,总的来说,这是一个好主意。 std lib的例外实际上并不是我认为是失败的。
当我上次设计一个异常层次结构时,我非常广泛地使用了MI,但是并没有从std lib的异常类派生。 在该层次结构中,您定义了抽象异常类,以便您的用户可以捕获它们,以及从这些抽象类派生的相应实现类以及实际抛出的实现基类。 为了使这更容易,我定义了一些可以完成所有艰苦工作的模板:
// 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
,我想我可以让exc_impl
类模板派生自std::exception
(或std lib异常层次结构中的任何其他类,作为可选模板参数传递),因为它永远不会派生自任何其他exc_impl
实例。 但那时候不需要这样,所以我从来没有想过。
你应该尝试boost :: exception
Boost Exception的目的是简化异常类层次结构的设计,并帮助编写异常处理和错误报告代码。
它支持将任意数据传输到catch站点,否则由于异常类型的无抛出要求(15.5.1)而非常棘手。 数据可以直接在throw-expression(15.1)中添加到任何异常对象,也可以在异常对象向上传播到调用堆栈时添加到任何异常对象。
在将异常对象传递给throw之后向异常对象添加数据的能力很重要,因为在检测到故障的上下文中,处理异常所需的一些信息通常是不可用的。
Boost Exception还支持N2179样式的异常对象复制,由boost :: throw_exception函数非侵入性地自动实现。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.