异常基本语法
异常基本概念
让一个函数在发现了自己无法处理的错误时抛出一个异常,然后它的(直接或间接)调用者能够处理这个问题,也就是将问题检测和问题处理相分离
异常处理就是处理程序中的错误.所谓错误是指在程序运行的过程中发生的一些异常事件(如0溢出,数组下标越界,所要读取的文件不存在,空指针,内存不足等)
C++的异常必须有函数进行处理,否则程序会中止
#include<iostream>
using namespace std;
int myDivision(int a,int b)
{
if(b==0)
{
return -1;
}
return a/b;
}
void test01()
{
int a=10;
int b=0;
//c语言处理异常,返回值不统一,返回值只有一个,无法区分是结果还是异常
//int ret=myDivision(a,b);
//if(ret==-1)
//{
// cout<<"异常"<<endl;
//}
}
int main()
{
test01();
return 0;
}
c++异常的处理关键字和语法
try throw catch
可以出现异常的代码放到try块中
利用throw抛出异常
利用catch捕获异常 catch(类型)如果想捕获其他类型catch(…)
如果捕获到的异常不想处理 则利用throw继续向上抛出
异常必须有函数进行处理 如果都不去处理 程序自动调用terminate函数中断
异常可以是自定义的数据类型
栈解旋
从try代码块开始,到throw抛出异常之前,所有栈上的数据都会被释放掉,释放的顺序和创建顺序相反,这个过程为栈解旋
异常接口声明
异常接口声明将严格的告诉你抛出的异常的数据类型
void func()throw(int,double)
{
throw 3.14;
}
如果出现下面这段代码
void func()throw()
{
throw 3.14;//会崩掉
}
//上面这段代码的意思是任何异常都不让抛出
异常变量的生命周期
#include<iostream>
using namespace std;
class MyException{
MyException()
{
cout<<"MyException的默认构造函数调用"<<endl;
}
MyException(const MyException &e)
{
cout<<"MyException的拷贝构造函数调用"<<endl;
}
~MyException()
{
cout<<"MyException析构函数调用"<<endl;
}
};
void doWork()
{
throw MyException();//先有了对象
}
void test01()
{
try
{
doWork();
}
catch(MyException e)//会调用拷贝构造函数拷贝一份给他,如果改成引用则不会调用拷贝构造函数只调用默认构造函数效率更高
{
cout<<"自定义异常捕获"<<endl;
}
}
int main()
{
test01();
return 0;
}
抛出的是throw MyException();catch(MyException e)调用拷贝构造,效率低
抛出的是throw MyException();catch(MyException &e)只调用默认构造函数,效率高(引用相当于起别名,也就是说还是起名字了,相当于就不会被提前释放掉)
抛出的是throw MyException();catch(MyException *e)对象会提前释放掉,不能在非法操作,如果不想被提前释放掉,则throw new MyException(),但是要自己delete
异常的多态使用
#include<iostream>
using namespace std;
//异常的基类
class BaseException()
{
public:
virtual void printError()=0;
};
//空指针异常
class NULLPointerException:public BaseException
{
public:
virtual void printError()
{
cout<<"空指针异常"<<endl;
}
};
//越界异常
class OutOfRangrException:public BaseException
{
public:
virtual void printError()
{
cout<<"越界异常"<<endl;
}
};
void doWork()
{
//抛出的异常不同,打印内容也不同
throw NULLPointerException();
throw OutOfRangeException();
}
void test01()
{
try
{
doWork();
}
catch(BaseException &e)
{
e.printError();
}
}
int main()
{
test01();
return 0;
}
C++标准异常库
异常名称 | 描述 |
---|---|
exception | 所有标准异常类的父类 |
bad_alloc | 当operator new and operator new[],请求分配内存失败时 |
bad_exception | 这是个特殊的异常,如果函数的异常抛出列表里声明了bad_exception异常,当函数内部抛出列表中没有的异常,这时调用的unexpected函数中若抛出异常,不论什么类型,都会被替换成bad_exception类型 |
bad_typeid | 使用typeid操作符,操作一个NULL指针,而该指针是带有虚函数的类,这时抛出bad_typeid异常 |
bad_cast | 使用dynamic_cast转换引用失败的时候 |
ios_base::failure | io操作过程出现错误 |
logic_error | 逻辑错误,可以在运行前检测的错误 |
runtime_error | 运行时错误,仅在运行时才可以检测的错误 |
logic_error的子类
异常名称 | 描述 |
---|---|
length_error | 试图生成一个超出该类型最大长度的对象时,例如vector的resize操作 |
domain_error | 参数的值域错误,主要用在数学函数中,例如使用一个负值调用只能操作非负的函数 |
out_of_range | 超出有效范围 |
系统标准异常
#include<iostream>
#include<stdexcept>//异常头文件
using namespace std;
class Person
{
public:
int age;
Person(int age)
{
if(age<0||age>150)
{
throw out_of_range("年龄必须在0~150之间");
}else{
this->age=age;
}
}
};
void test01()
{
try
{
Person p(151);
}//catch(out_of_range &e)
catch(exception &e)//利用多态的形式
{
cout<<e.what()<<endl;//打印异常错误提示信息
}
}
int main()
{
test01();
return 0;
}
编写自己的异常类
#include<iostream>
using namespace std;
//编写自己的异常类
class MyOutOfRangeException:public exception
{
public:
string errorinfo;
MyOutOfRangeException(const char* str)
{
//const char*可以隐式转换为string,但反过来报错
this->errorinfo=str;
}
virtual const char* what() const
{
//如何将string转为const char*
return errorinfo.c_str()
//return errorinfo;
}
};
class Person
{
public:
int age;
Person(int age)
{
if(age<0||age>150)
{
throw MyOutOfRangeException("年龄必须在0~150之间");
}else{
this->age=age;
}
}
};
void test01()
{
try
{
Person p(151);
}
catch(exception &e)//利用多态的形式
{
cout<<e.what()<<endl;//打印异常错误提示信息
}
}
int main()
{
test01();
return 0;
}