boost库实用工具之exception

来源:互联网 发布:手机淘宝花呗怎么开通 编辑:程序博客网 时间:2024/06/05 23:40
    异常是C++处理错误的重要机制,他改变了传统的使用错误返回值的处理模式,简化了函数的接口和调用代码,有助于编写整洁,优雅,健壮的程序。C++标准库中定义的标准异常类std::exception及其一些子类是整个C++语言处理的基础。    而boost.exception 库针对标准库中异常类的缺陷进行了强化,提供了<<操作符重载,可以向异常传入任意数据,有助于增加异常的信息和表达力,其中部分特性已经加入C++11标准。    exception位于名字空间boost中,为了使用exception,需要包含头文件boost/exception/all.hpp

标准库中的列表

为了使用boost.exception,我们需要先了解c++标准规定的异常体系。
c++标准中定义了一个异常基类std::exception和try/catch/throw异常处理机制,std::exception又派生出若干子类,用以描述不同种类的异常,如bad_alloc, bad_cast, out_or_range等,共同构建了C++异常处理框架。
C++允许任何类型作为异常抛出,但在std::exception出现后,我们应该尽量使用它,因为std::exception提供了一个很有用的函数what(),可以返回异常所携带的信息。
有时我们需要定义自己的错误信息,我们需要继承std::exception及其子类。例如:

class my_exception : public std::logic_error{private:    int err_no;//错误信息码public:    my_exception(const char* msg, int err):        std::logic_error(msg)        , err_no(err)    {        //    }    int get_err_no() { return err_no; }};

如果系统需要很多不同种类的异常时,这种方法就会成为负担——需要编译异常处理大量代码。
而且这种解决法还存在一个问题:很多时候当异常发生时不能获得有异常的完全诊断信息,而标准库的异常类一旦出现,它就成了一个“死”对象,程序失去了对它的控制能力,只能使用它或者再抛出一个新的异常。
boost.exception针对这些异常定义了新的异常类boost.exception完善了c++的异常处理机制。

类摘要

exception库提供了两个类:exception和error_info,他们是exception库的基础。

exception

class exception{public:    exception();    exception(exception const& x);    virtual ~exception();private:    template<class E,class Tag,class T>    friend E const& operator<<(E const&, error_info<Tag, T> const&);};typename value_type* get_error_info(E&x);

注意:它是一个抽象类,几乎没有公开的成员函数。除了它的子类,任何人都不能创建或者销毁它,这保证了exception不被误用。
exception的重要能力在于其友元操作符<<,可以存储error_info对象的信息,存入的信息可以用自由函数get_error_info<>()随时取出来。这个函数返回一个存储数据的指针,如果exception里米有这一种类型的信息返回空。
exception特意没有从std::exception继承。

error_info

class exception{public:    exception();    exception(exception const& x);    virtual ~exception();private:    template<class E,class Tag,class T>    friend E const& operator<<(E const&, error_info<Tag, T> const&);};typename value_type* get_error_info(E& x);error_info 提供了向异常类型添加信息的通用解法。第一个模板类型参数Tag是一个标记,他通常(最好)是一个空类,仅用来标记error_info类,使他在模板实例化时生成不同的类型。第二个参数T是真正存储的信息数据,可以用成员函数value()访问

向异常传递信息

exception和error_info被设计为配合std::exception一起工作,自定义的异常类可以安全地从exception和std::exception多重继承,从而获得两者的能力。
注意exception是抽象的,我们必须自己定义它的子类才能使用它,如前所述,exception必须使用虚继承的方式。通常,继承完成后自定义异常类的实现也就完成了,不需要“画蛇添足”地向它增加成员函数或者成员变量。这些都已经由exception完成了。例如:

struct my_excpetion:    virtual std::exception,//虚继承,struct 默认public继承    virtual boost::exception // 虚继承,struct 默认public继承{    //空实现,不需要实现代码。};

接下来我们需要定义我们要存储的信息–使用模板类,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()函数获取。
示范代码如下:

struct my_excpetion:    virtual std::exception,//虚继承,struct 默认public继承    virtual boost::exception // 虚继承,struct 默认public继承{    //空实现,不需要实现代码。};typedef boost::error_info<struct tag_err_no, int> err_no;typedef boost::error_info<struct tag_err_str, string> err_str;void case1(){    try    {        try {            // 抛出异常,存储信息码            throw my_excpetion() << err_no(10);        }        catch (my_excpetion& e)        {            //获取异常内存储的信息            cout << *get_error_info<err_no>(e) << endl;            cout << e.what() << endl;            e << err_str("other info"); //向异常内追加信息            throw; //然后再次抛出异常        }    }    catch (my_excpetion& e) // function_try 的捕获代码    {        // 获得异常信息        cout << *get_error_info<err_str>(e) << endl;    }}

错误信息类

处理异常的一个工作是定义错误类型,我们用typedef来具体化error_info模板类。这通常比较麻烦,exception库特意预定义了若干个定义好的错误信息类

typedef error_info<...> errinfo_api_function;typedef error_info<...> errinfo_at_line;typedef error_info<...> errinfo_errno;typedef error_info<...> errinfo_file_handle;typedef error_info<...> errinfo_file_open_mode;typedef error_info<...> errinfo_type_info_name;

它们可以用于常见的调用API,行号,错误代码,文件handle,文件名等错误信息的处理。例如

try {    throw my_excpetion() << errinfo_api_function("call api") << errinfo_errno(10);}catch (boost::exception& e){    cout << *get_error_info<errinfo_api_function>(e);    cout << *get_error_info<errinfo_errno>(e);}

另外,exception库还提供了三个预定义的错误信息类型,但命名规则略有不同:
typedef error_info<…> throw_function;
typedef error_info<…> throw_file;
typedef error_info<…> throw_line;
这三个错误信息类,主要用于存储源代码的信息,配合宏BOOST_CURRENT_FUNCTIONFILELINE使用,可以获取函数名,源文件名和源代码行号。

如果这些预定义的还不能满足要求,我们还需要用typedef来定义我们错误信息。
可以用宏DEFINE_ERROR_INFO。

#define DEFINE_ERROR_INFO(type, name) \    typedef boost::error_info<struct tag_##name, type> nameDEFINE_ERROR_INFO<int,err_no>; 就相当于typedef boost::error_info<struct tag_err_no,int >err_no

包装标准异常

exception库提供了一个模板函数enable_error_info(T& e), 其中T是标准异常类或者其他自定义类型。它可以包装类型T,产生从boost::exception和T派生的类,从而不修改原异常处理体系的前提下获得boost::exception的所有好处。如果类型T已经是boost::exception的子类,那么enable_error_info将返回e的一个拷贝。
enable_error_info()通常在程序中已经存在异常类的场合,对这些异常类的修改很困难甚至不可能(比如已经编译成库)。这时候enable_error_info()就可以包装原有的异常类,从而很容易的在不改变原有代码的基础上把boost::exception集成到原有的异常体系中去。

//自定义的一个异常类,未使用boost::exceptionstruct my_err{};void cast2(){    try {        //使用enable_error_info包装自定义的异常        throw enable_error_info(my_err()) << errinfo_errno(10);        throw enable_error_info(std::runtime_error("runtime"))        << errinfo_at_line(__LINE__);    }    catch (boost::exception& e)//这里必须使用errinfo_errno(10)来捕获    {        cout << *get_error_info<errinfo_errno>(e) << endl;    }}

使用函数抛出异常

exception库在头文件

原创粉丝点击