c++ --异常

1概念

1.1基本思想:

  • 让一个函数发现自己无法处理的的错误抛出一个异常 然后将它的调用者能够处理这个函数,将问题检测和问题处理分离
  • 异常处理就是:
    处理程序中的错误 所谓错误是指在程序运行的过程中发生的一些异常事件(IO溢出,数组下标越界 所读取的文件不存在,内存不足)

1.2特点

  • 不干扰正常的返回值。
  • 必须处理异常。
  • 只要抛出异常,异常后的代码不再执行。
  • 异常的所抛出与经过的栈都会销毁。

1.3语法

  • 异常分为两个部分:抛出异常与捕获并处理异常。
抛出异常
throw 表达式;
捕获并处理异常
try {  
        // 保护代码 包含可能抛出异常的语句;  
} catch (类型名 [形参名]) {  
        // catch块 处理异常
}

1.4C语言措施

  • C语言如何表示错误
    • 函数返回值
    • 全局变量errno

1.5示例

#include<iostream>
using namespace std;

int myDivide(int a,int b){
	if(b==0){
		//抛出异常
		throw -1;//捕捉异常不在乎你抛出的值只在乎你抛出的值的类型
		//抛出一个异常整个函数就结束了 后面的throw
		throw 1.23;
		throw 'a';
	}		
	return a/b;
}
void test(){
	int a=10;
	int b=-0;	
	try{
		myDivide(a,b);
	}
	catch(int){//int:为什么是int是因为抛出的时int型			
		cout<<"int 类型的异常"<<endl;
		throw 1.5;

	}
	catch(double){
		cout<<"double 类型的异常"<<endl;
	}
	catch(...){
		cout<<"其他 类型的异常"<<endl;
	}
}
int main(){
	//throw 抛出的异常必须要catch处理 程序会自动调用一个程序中断函数,让程序中断掉	
	try{
		test();
	}
	catch(int){//int:为什么是int是因为抛出的时int型
		cout<<"int 类型的异常"<<endl;

	}
	cout<<"main return" <<endl;
}

2其他知识点

2.1自定义异常类

#include<iostream>
using namespace std;
class MyException{
public:
	void printfError(){
		cout<<"我自己的异常类的错误"<<endl;	
	}

};
class Person{
public:	
	Person(){
		cout<<"pereson 的构造函数"<<endl;
	}
	~Person(){
		cout<<"pereson 的系造函数"<<endl;
	}

};
int myDivide(int a,int b){
	if(b==0){
		//栈解璇 从try代码块开始,到throw抛出异常前 所有栈上的对象都被释放掉
		Person p1;
		Person p2;
		cout<<"aaaaa"<<endl;
		throw MyException();
	}		
	return a/b;
}
void test(){
	int a=10;
	int b=-0;	
	try{
		myDivide(a,b);
	}
	catch(MyException e){
		e.printfError();
	}
	catch(...){
		cout<<"其他 类型的异常"<<endl;
	}
}

2.2栈解璇

//栈解璇 从try代码块开始,到throw抛出异常前 所有栈上的对象都被释放掉
在这里插入图片描述

2.3异常接口说明

返回值类型 函数() throw(异常列表);
  • 指定函数可以抛出何种异常,如果没有throw(异常列表)默认可以抛出所有异常。异常列表为空throw()。指定函数不抛出异常,指定什么异常就必须抛出什么异常。

2.4异常变量的声明周期

  • 建议使用引用的方式
/*
 在catch()中类型如下
 MyException e 会调用拷贝构造函数
MyException &e 引用方式 建议用这种方式 节省开销
MyException *p 指针方式 接受抛出&MyException()匿名对象 对象被释放掉 不可以在操作e
MyException *p 指针方式 接受抛出的new MyException()堆区创建的对象 记得手动释放 delete e
 * */
#include<iostream>
using namespace std;
class MyException{
public:
	MyException(){
		
		cout<<"构造异常类"<<endl;	
	}
	MyException(const MyException& e){
		cout<<"拷贝构造异常类"<<endl;
	}	
	void printfError(){
		cout<<"我自己的异常类的错误"<<endl;	
	}
	~MyException(){
		cout<<"希构异常类"<<endl;	
	}

};
int myDivide(int a,int b){
	if(b==0){
		throw MyException();
	}		
	return a/b;
}
void test(){
	int a=10;
	int b=0;	
	try{
		myDivide(a,b);
	}
	catch(MyException& e){
		e.printfError();
	}
	catch(...){
		cout<<"其他 类型的异常"<<endl;
	}
}
int main(){
	MyException e=test();
	cout<<"main return" <<endl;
}

3标准异常类

在这里插入图片描述

  • 原理:异常的多态使用

3.1特点

  • 1:所有的体系函数中都有构造函数 复制构造函数 和复制运算符重载
  • 2:logic_error,runtime_error及其子类,他们的构造函数接受一个string类型的参数的形式参数 用于异常的描述
  • 3:所有的异常类都有what()方法 返回const char *类型的值 描述异常信息

3.2exception派生

异常类作用
logic_error逻辑错误,在程序运行前可以检测出来
runtime_error运行时错误,仅在程序运行中检测到

3.2.1逻辑异常logic_error派生

异常类作用
domain_error违反了前置条件
invalid_argument指出函数的一个无效参数
length_error指出有一个超过类型size_t的最大可表现值长度的对象的企图
out_of_range参数越界
bad_cast在运行时类型识别中有一个无效的dynamic_cast表达式
bad_typeid报告在表达试typeid(*p)中有一个空指针p

3.2.2运行时runtime_error派生

异常类作用
range_error违反后置条件
bad_alloc存储分配错误

3.3编写自己的异常类

/*
 1:所有的体系函数中都有构造函数 复制构造函数 和复制运算符重载
 2:logic_error,runtime_error及其子类,他们的构造函数接受一个string类型的参数的形式参数 用于异常的描述
3:所有的异常类都有what()方法 返回const char *类型的值  描述异常信息
 * */
#include<iostream>
#include<stdexcept>//标准异常
using namespace std;

//自己的异常类
class MyoutofRange:public exception{
public:	
MyoutofRange(char * errorinfo){
		this->my_errorinfo=string(errorinfo);
	}
	MyoutofRange(string errorinfo){
		this->my_errorinfo=errorinfo;
	}
	virtual const char* what( )const{
		return this->my_errorinfo->c_str();
	}
	virtual ~MyoutofRange(){

	}
	//保存用户传入的异常字符传
	string  my_errorinfo;
};
class Person{
public:
	Person(int age){
		if(age<0||age>150){
			//抛出异常
			throw MyoutofRange("我的异常类--<F9>年龄必须在0——150");
		}
		m_age=age;
	}
int m_age;
};
void test1(){
	try{
		Person p1(152);
	
	}
	catch(exception& e){
		cout<<e.what()<<endl;
	}

}
int main(){
	test1();
	
	cout<<"main return" <<endl;
}

4构造函数、析构函数的异常处理

  • 构造函数可以抛出异常,此时不会调用析构函数,所以如果抛出异常前,申请了资源,需要自己释放。
  • C++标准指明析构函数不能、也不应该抛出异常。
  • C++标准规定,构造函数失败,析构函数不会执行。就是说在构造函数抛出异常前分配的资源将无法释放。

如果析构函数抛出异常,则异常点之后的程序不会执行,如果析构函数在异常点之后执行了某些必要的动作比如释放某些资源,则这些动作不会执行,会造成诸如资源泄漏的问题。
通常异常发生时,c++的机制会调用已经构造对象的析构函数来释放资源,此时若析构函数本身也抛出异常,则前一个异常尚未处理,又有新的异常,会造成程序崩溃的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值