C++异常处理

异常处理的基本概念

  • 异常处理机制:暂缓问题处理,不在当前函数中处理,在它的调用者中处理(类似先上车,后补票)

  • 什么是异常:任何东西都可以认为是异常,错误只是异常的一种 - - - 出现一种情况让程序不能正常运行,这种情况我们都可以把它当做异常

  • 异常一旦被抛出,不做处理,如果引发异常,会调用默认abort函数终止程序

  • 捕获和处理异常

    • throw 抛出异常: (可以理解为返回一个值,值是任何类型都可以,是我们处理异常的一个参照)

    • try(检查,捕获异常)和catch(处理异常): 必须是一起出现,并且它们的括号{ }不能省略

什么是异常?怎么抛出?

//求a和b的余数    怎么抛出异常
int division(int a,int b)
{
    if(b==0)
        throw 0;   //抛出一个值(任意)--->之后处理
    return a/b;
}
void print(int a,int b)
{
    cout << division(a,b);
}
int main()
{
    print(1,0);    //引发异常不做处理

}
/*除数不能为0 把b==0 的情况称为异常 b==0 时代码不成立会中断当前程序*/

异常一旦被抛出,不做处理,如果引发异常,会调用默认abort函数终止程序(引发了标准库中的异常)

捕获和处理异常

//try 与catch必须是一起出现的,并且他们各自的括号{}不能省略
try
{
	//正常需要检查是否存在异常的代码 
}
catch(类型)     //理解为switch中case语句 如果存在异常会跳到catch的位置
{
    //处理是根据抛出数据类型决定如何处理 匹配项:匹配抛出异常的类型
}

//一个try可以对应多个catch
try
{
	//...    
}
catch(int)
{
	    
}
catch(double)
{
    
}
catch(string)
{
	    
}
//catch和if else_if 执行机制一样,只能执行一个匹配项

小知识:

  • 对try{ }   catch(){ } 的理解:在当前位置引发异常,直接从这个位置跳到catch的位置执行catch的代码 - - - 类似 switch case 语句

  • catch中int和char不会做类型转换

  • 抛出两个相同的类型异常不被允许,报错:"int":由"int"在第 n 行上被捕获

int division(int a,int b)
{
    if(b==0)
        throw 0;    
    return a/b;
}
void print(int a,int b)
{
    cout<<division(a,b);
}
int main()
{
    try                          //检查异常
    {
        print(1,0);     
        cout<<"别的代码"<<endl;   //会直接跳到catch,这一句不会运行
    }    
    catch(int)                   //抛出的是int类型,捕获int类型
    {
        cout<<"除数不能为0"<<endl;
    }
}

/*输出*/

除数不能为0

程序中能存在多个异常,但是只能引发1个异常,不可能同时引发多个异常

不存在异常的描述 - - - 标识性作用    

  • throw( )

  • noexcept

//某个函数不存在异常,在某个函数后面用throw() 描述表示它不存在异常
void  print() throw() 
{
	cout << "当前函数不存在抛出异常操作" << endl;
}
void printData() noexcept 
{
	cout << "c++新标准中的关键字: 不存在抛出异常" << endl;
	//throw 0;  报错:一旦说明没有异常就不能写抛出操作
}

删减符 . . .

任何类型的异常都捕获    不管抛出啥,在哪里抛出的,只要引发异常都可以捕获到

catch(...)
{
    cout <<"捕获任何类型的异常"<< endl;
}

异常处理中的传参操作 - - - 可以写一个变量进去

  • catch(int a)                     

  • 隐藏了一个传参操作 可以传任何类型,包括自定义类型都可以 

  • 想要处理抛出字符串的异常处理,注意string类型与const char* 类型区别

抛出字符串,隐藏了一个传参操作  

int divisor(int a, int b) 
{
    if (b == 0)
		throw "除数不能为0"; //解析为char* 类型 catch中不能当作string处理
	if(b == 1)
		throw "除数不能为1"; /*不同问题的抛出,不能用固定类型(int、char...), 可以选择
          抛出不同字符串处理 string1,string2,string3...(通过传参的方式去描述问题) */
	if(b == 2)
		throw "除数不能为2";
    	return a / b;
}
int main()
{
	try
	{
		divisor(1, 0);   
	}
	catch (string str)    //把throw的内容赋值给str    str = "除数不能为0"
	{
		cout << str << endl;
	}
}
//调用abort函数终止程序
//改正:
	catch (const char* str)    
	{
		cout << str << endl;
	}
/*输出*/

除数不能为0

函数中隐藏的传参操作时注意string 和const char* 的处理 - - - 出现类型不匹配的问题,c++对传参类型要求更严格,想要捕获string类型的异常,需要构造无名参数作捕获处理

int divisor(int a, int b) 
{
	if(b==2)
		throw string("除数不能为2");  //捕获对象需要自己触发
	return a / b;
}

int main()
{
	try
	{
		divisor(1, 2);
	}
	catch (string str)      //如果想捕获string类型,需要自己构造一个string对象返回
	{
		cout << str << endl;
	}
}

/*输出*/

除数不能为2

可以抛出自己类的对象 - - - 传自定义类型

定义一个错误类Error,程序中所有错误都归到Error类中 - - - 在做数组插入 & 删除时要考虑里面是否为空或者是满的状态 把数组满了的情况称为一种异常

class Error 
{
public:
	Error(const char* str = "未知错误") :str(str) {}    //构造函数
	const char* what()const 
	{
		return str.c_str();                             //成员函数
	}
protected:
	string str;
};

//实现数组的插入,下标可能存在问题(数组下标溢出) 数组最大下标!=个数
//插入的数组 当前数组长度(元素个数) 插入的元素 最大数组长度(最大长度为3|最大下标为2)  
void insertArray(int array[], int* curNum, int posData,int maxLength) 
{
	if (*curNum >= maxLength)  //3>=3 注意3>3的情况,还是会做插入操作
	{
		throw  Error("数组下标溢出!"); //当前数组满了当作是异常抛出
	}
	//0 1 2
	array[*curNum] = posData;  //array[3]=3 下标没问题把元素插到数组中即可
	(*curNum)++;               //当前元素长度增加
}

int main()
{
    try
	{
		int array[3] = { 0,0,0 };
		int curNum = 0;
		for (int i = 0; i < 4; i++) 
		{
			insertArray(array, &curNum, i, 3);
		}
	}
	catch (Error str)         //抛出自己的对象
	{
		cout << str.what() << endl;
	}
    return 0;
}

标准库当中的异常类

 #include<exception>    //父类(基类)

子类很多,子类描述的问题不同而已

例: const char* _ptr; 用于描述标准库当中异常的字符串,用字符指针存放那个字符串

            what( )方法  用于返回数据成员的 虚函数 & 不存在异常

            return _ptr ? _ptr : "unknow";判断char* 类型的指针是不是为空,不等于空,返回你描述的错误,等于空,返回"unknow exception"(如果没有传参,返回未知错误"unknow")

引发标准库中的异常 - - - 内存申请失败

  • 发现代码出现abort( )错误,可以通过这种方式找到,这里是针对内存申请失败做了单一处理,如果不做处理,会直接调用abort()函数终止程序

  • c++ 整个异常处理机制中有一个专门的类去做管理,和多态的设计方式一样,存在新的问题,只需要拓展代码,而不需要修改原来代码

class Exception 
{
public:                                 //构造函数 干掉常属性
	Exception(const char* ptr="UNKNOW") :ptr(const_cast<char*>(ptr)){} 
	virtual const char* what() const    //父类中的what方法是虚函数 & 不存在异常
	{
		return ptr;
	}
protected:
	char* ptr;    //用来存放字符串
};
//子类继承父类    
class Bad_alloc :public Exception
{
public:                                //调用父类的构造函数抛出bad exception
	Bad_alloc(const char* _Message = "bad exception") :Exception(_Message) {} 
protected:
};
//子类继承父类   
class Run_time :public Exception
{
public:
	Run_time(const char* _Message = "run_time error") :Exception(_Message) {}
protected:
};

int main() 
{
	try 
	{
		while (1) 
		{                     //一直做内存申请不做释放最后一定会内存申请失败
			int* p = new int[1024*1024*10];
		}
	}
	catch (bad_alloc& object) /* 内存申请失败,调用bad_alloc 标准库中的异常
        创建一个对象接收一下,子类中的what()方法调用父类中的what()方法打印*/
    {
		cout << object.what() << endl;    //使用标准库中的异常
	}
	return 0;
}
/*输出*/

bad allocation //调用时抛出的 bad allocation 是子类对象调用继承下来的what()方法

//写代码出现莫名的中断 大原因是不做异常处理引发了abort函数中断程序

标准库中传两个参数,一个参数起到标识作用,由于:引发了不同的错误,不同错误对应了不同的错误编码 对这些错误有特定的描述 ---> 工具 ---> 错误查找 ---> 输入错误编码

值:3

错误信息:系统找不到指定的路径

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qiuqiuyaq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值