4.9.3 向异常传递信息
exception和error_info被设计为配合std::exception一起工作,自定义的异常类可以安全地从exception和std::exception多重继承,从而获得两者的能力。
因为exception被定义为抽象类,因此我们的程序必须定义它的子类才能使用它,如前所述,exception必须使用虚继承的方式。通常,继承完成后自定义异常类的实现也就结束了,不需要"画蛇添足":向它增加成员变量或者成员函数,这些工作都已经由exception完成了。例如:
- struct my_exception : //自定义异常类
- virtual std::exception, //虚继承
- virtual boost::exception //虚继承
- {}; //空实现,不需要实现代码
接下来我们需要定义异常需要存储的信息--使用模板类error_info。用一个struct作为第一个模板参数来标记信息类型,再用第二个模板参数指定信息的数据类型。由于error_ info<>的类型定义较长,为了使用方便起见,通常需要使用typedef。
下面的代码使用error_info定义了两个存储int和string的信息类:
- //异常信息的类型
- typedef boost::error_info<struct tag_err_no, int> err_no;
- typedef boost::error_info<struct tag_err_str, string> err_str;
当发生异常时,我们就可以创建一个自定义异常类,并用<<操作符向它存储任意信息,这些信息可以在任何时候使用get_error_info()函数提取。
示范exception用法的代码如下:
- #include <boost/exception/all.hpp>
- ... //之前的异常类和信息类定义
- int main()
- try //function-try块
- {
- using namespace boost;
- try
- {
- //抛出异常,存储错误码
- throw my_exception() << err_no(10);
- }
- catch (my_exception& e) //捕获异常,使用引用形式
- {
-
- //获得异常内存储的信息
- cout << *get_error_info<err_no>(e)<<endl;
- cout << e.what()<<endl;
- e << err_str("other info"); //向异常追加信息
- throw; //再次抛出异常
- }
- }
- catch(my_exception& e) //function-try的捕获代码
- {
- cout << *get_error_info<err_str>(e)<<endl; //获得异常信息
- }
代码里的注释已经解释了很多东西,我们再来看一下。
程序首先定义了一个异常类my_exception,然后使用typedef定义了两种异常信息:err_no和err_str,用int和string分别存储错误码和错误信息。main()函数使用function-try块来捕获异常,它把整个函数体都包含在try块中,可以更好地把异常处理代码与正常流程代码分离(较老的编译器可能不支持function-try的用法)。
throw my_exception()语句创建了一个my_exception异常类的临时对象,并立刻使用<<向它传递了err_no对象,存入错误码10。随后,异常被catch块捕获,自由函数get_ error_info <err_no>(e)可以获得异常内部保存的信息值的指针,所以需要用解引用操作符*访问。
异常还可以被追加信息,同样使用操作符<<,最后在function-try的catch块部分,异常被最终处理,程序结束。