wangqiuji

 

C++异常处理

一、异常处理

  • 程序的错误大致分三种:语法错误、逻辑错误、运行时错误

  • 运行时错误发生在程序运行期间发生的问题:除零、内存分配失败、非法访问内存、文件不存在、数组越界

  • C++的异常处理机制就是为了解决运行时错误

  • C语言中运行时错误如果不管,系统会执行默认操作,可能会让程序终止产生崩溃,也可能不终止,但是运行结果不正确

  • C++提供的异常处理机制,能够捕捉到运行时错误,至少提供了告诉调用者发生了什么事情导致终止的方式,然后再终止

二、如何抛异常

throw 数据;    
  • 数据可以是任意类型

  • 不要抛出局部变量的地址,因为该地址有可能被释放

  • 抛出的数据不是直接传递给捕获的变量,而是先创建一个匿名对象存储该数据,然后传递该匿名对象

三、如何捕获异常

try{
    //可能会产生异常的代码或函数调用
}catch(类型1& 变量名){
    //进行异常处理1
}catch(类型2& 变量名){
    //进行异常处理2
}···
  • 如果使用 ’类型 变量名 ‘ 方式捕获异常,会对匿名对匿名对象再拷贝一次,浪费资源时间,所以一般使用引用获取该匿名对象,可以减少一次拷贝

四、异常说明(异常规范)

返回值 函数名(形参列表)[异常说明throw (类型名1,类型名2)]
{

}
例如:
void func(void)throw(类型1,类型2)
void func(void)throw()    //表示不抛异常
  • 异常说明相当于该函数的限制或承诺,只抛出说明过的异常类型,如果抛出说明外的类型,可以抛出,但是不能接住

  • 不同编译器对异常说明的实现不同,有的听从,有的不听从

  • 异常说明是C++98的一项功能,C++11后就抛弃了,不建议使用

  • C++11中使用 void func(int x) noexpect 替代

五、标准异常

  • C++已经定义好的异常类,当对应的异常发生时,会自动地抛出定义好的对应的异常类对象

  • std::exception  所有标准异常类的父类,能够捕获所有的标准异常

  • std::bad_alloc  new分配内存失败时抛出的异常,std::bad_array_new_length 是它的子类 new分配内存数量有误会抛出

  • std::bad_cast  该异常可以通过 dynamic_cast 抛出

    需要#include < typeinfo >

  • std::bad_typeid 该异常可以通过typeid 抛出

    • 当获取具有多态属性的类型指针解引用的类型时,如果不能确定解引用后是哪个类型时,会抛出该异常

      Base* b = new Base;
      Base* b1 = new Son;
      Base* b2 = NULL;
      typeid(*b);      //类型 Base
      typeid(*b1);     //类型 Son
      typeid(*b2);     //抛异常
      

六、自定义异常类

通过设计一个继承了exception的异常类,可以个性化地抛出想要的异常

#define ZZERROR(...) ZZError(__TIME__,__FILE__,__func__,__LINE__,__VA_ARGS__)

class ZZError : public exception
{
    string time;
    string file;
    string func;
    size_t line;
    string error;
public:
    ZZError(const string& time,const string& file,const string& func,size_t line,const string& error):time(time),file(file),func(func),line(line),error(error){}
    ~ZZError(void){}

    const string& what(void)
    {
        return error;
    }

    friend ostream& operator<<(ostream& os,const ZZError& err)
    {
        return os << "time:" << err.time << " file:" << err.file <<" func:" << err.func << " line:" << err.line << " error:" << err.error;
    }
};

七、使用异常需要注意的问题

  1. 不要抛出局部变量、对象的地址,而是抛出变量、对象本身

  2. 建议使用引用的方式来捕获异常,减少一次拷贝

  3. 不要在构造函数、析构函数中抛异常

  4. 在捕获异常时,先捕获子类类型,再捕获父类类型

posted on 2023-09-01 20:47  翻斗花园牛大爷!  阅读(60)  评论(0编辑  收藏  举报

导航