【C++】异常处理

文章详细阐述了异常与Bug的差异,异常处理的核心在于try、throw和catch机制,包括异常捕获顺序、处理所有异常的catch(...)以及函数中的异常处理。同时,介绍了C++的标准异常类和如何自定义异常类,强调了异常处理在确保程序健壮性中的重要性。
摘要由CSDN通过智能技术生成

目录

 

1.异常 vs Bug

2.throw 和 try - catch

2.1异常处理 Exception Handle

2.2throw 和 try - catch

2.3 多个catch块:异常捕获顺序

2.4捕获一切异常:catch(...)  

2.5函数中抛出异常      

2.6函数异常限定符 

3.自定义异常类

3.1C++标准异常类

3.2自定义异常类

4.例题


1.异常 vs Bug

Bug:程序出错、有 逻辑错误 ,无论输入数据是什么都无法得到正确结果
(比如程序员在写除法代码,除号写成乘号,无论用户输入啥数据得到的结果都是错误的)
异常:程序逻辑是正确的,但遇到了 正常范围之外 的输入数据而发生意外中断
对于Bug:程序员可控,越用心进行开发/走查/测试,Bug越少
对于Exception:程序员不可控,需要代码中设置针对异常情况的 保护 措施
网络应用:网络连通性、时延等不可控因素对于程序来说是异常
游戏:玩家打出极限操作、突破预先设置的情况是异常
数据分析:数据缺失值、未曾料想的特殊值等情况是异常
......
总之,程序正确编译了,也能按照既定逻辑执行功能,但是遇到了合法范围外的数据
导致程序失去 确定性 而中断

这个时候我们需要写一种保护程序,使之发生异常的时候不要终端,与其卡死,不如继续走下去

2.throw 和 try - catch

2.1异常处理 Exception Handle

异常导致程序失去确定性,不知道怎么继续下去了
• 异常保护:引导程序继续走下去,再不济也要做好收尾工作( 如释放占用的内存 ),体面结束
try -         throw -       catch
保护         抛出           捕获

              • 抛出异常    • 谁来捕获

                                   • 处理完从哪继续
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
int main()
{
	int a = 0;
	int b = 0;
	int c = 0;
	cin >> a >> b;
	try
	{
		if (b == 0)
		{
			throw(string("b is 0,exception throw"));

		}
		c = a / b;
	}
	catch (string e)
	{
		cout << e << endl;
		c = 0;
	}
	cout << "c=" <<c<< endl;
	return 0;
}

2.2throw 和 try - catch

throw: 使用throw语句主动立即抛出一个异常 对象 (但不一定throw才抛异常,如n/0)
try: 保护一个语句块,后跟 一个或多个 catch块。try块中抛出异常不会立刻中止程序而是寻找catch处理
catch: 捕获 指定 异常并进行处理,处理完 不会再返回 try块,直接离开try-catch继续执行

 

try
{
// 被保护的代码段,可以理解为试一试,看能否成功运行
throw(异常对象);
}
catch(期望捕获类型 变量名)
{
// 处理异常的代码段
}
其中异常对象可以是任何东西,但通常是 std::exception 的子类对象
try
{
    throw(1);
    cout << "After throw";//不会被执行
}
catch(int e)
{
    cout << e;//会输出1
}
// catch处理完从这里继续

2.3 多个catch块:异常捕获顺序

try 
{
    ... 
    throw(something);
    ... 
}
catch( Type1 e1 )
{
// catch 块1
}
catch( Type2 e2 )
{
// catch 块2
}
... 
catch( Type3 eN ) 
{
// catch 块N
}
• 从上到下依次尝试,直至类型匹配
• 一个异常只会被捕获一次

 

特别注意抛出对象是继承类,细节注意
若 A←B←C,哪种catch块排序合理?
1.对
try { ... }
catch( C e) { ... }
catch( B e) { ... }
catch( A e) { ... }
2.错
try { ... }
catch( A e) { ... }
catch( B e) { ... }//不可能捕获到东西
catch( C e) { ... }//不可能捕获到东西

2.4捕获一切异常:catch(...)  

try
{
    throw(something);
}
catch( Type1 e1 )
{
// catch 块1
}
catch( Type2 e2 )
{
// catch 块2
}
catch(...)
{
// 处理任何异常
}
• catch(...)能捕获一切异常,它后面的其他catch块等于没写
• 因此catch(...)应放在多个catch块的最后一个

2.5函数中抛出异常      

void funcA()
{
    try
    {
        funcB();
    }
catch (E6 e) { }
catch (E7 e) { }
// a处
}
void funcB()
{
    try
    {
        funcC();
    }
catch (E4 e) { }
catch (E5 e) { }
// b处
}
void funcC()
{
    try
    {
        E6 e;
        throw(e);
    }
catch (E1 e) { }
catch (E2 e) { }
catch (E3 e) { }
// c处
}

 

2.6函数异常限定符 

异常限定符:显式地指明是否允许函数抛出(哪些)异常    

void func1 () throw() ;--------------------------->什么都不允许抛出
void func2 () throw(int,double) ;-------------->允许抛出int或double
void func3 () throw(…) ;------------------------>允许抛出任何东西

3.自定义异常类

3.1C++标准异常类

虽说我们可以手动throw,抛出什么都可以,但一些常见的程序错误是C++自身抛出的(如除以零)
C++ 根据错误分类根据预设了一系列 标准异常 ,定义在 <exception> 中
它们以 父子类 层次结构组织,都在名字空间 std 下

3.2自定义异常类

自定义异常类通常继承自std::exception,并重写一些方法,比如what()
通常在自己编写的程序中会根据业务需求自定义异常类
自定义异常类例子:三角形异常类
#include<iostream>
using namespace std;
class TriangleException :public exception
{
public:
	float a;
	float b;
	float c;
	TriangleException(float a,float b,float c):a(a),b(b),c(c){}
	const char* what()const override
	{
		return "Invalid triangle exception!";
	}
};
//通过海伦公式计算三角形面积
float get_triangle_area(float a, float b, float c)throw(TriangleException)
{
	if (a + b <= c || a + c <= b || b + c <= a)
	{
		throw(TriangleException(a, b, c));
	}
	float p = (a + b + c) / 2.f;
	float s = p * (p - a) * (p - b) * (p - c);
	return sqrtf(s);
}
int main()
{
	float a, b, c, result;
	cin >> a >> b >> c;
	try
	{
		result = get_triangle_area(a, b, c);
	}
	catch(TriangleException e)
	{
		cout << e.what() << endl;
		return 0.f;
	}
	cout << "result=" << result << endl;
	return 0;
}

4.例题

Key 1 :try-throw-catch分别用于保护代码段、手动抛出异常与捕获异常
Key 2 :抛出的异常会按照其类型被首个匹配的catch块捕获(若有)
Key 3 :抛出的异常只会在首次匹配的catch块处被捕获一次
Key 4 :catch(...){ } 能捕获任何异常
1.关于C++的异常处理,正确的说法是:A
A.try必须和catch连用
B.throw必须和catch连用 (抛出异常不一定有匹配的catch捕获)
C.try语句块中必须有throw
D.try-throw-catch这三个关键字必须一起使用
分析:异常对象可以通过throw主动抛出,也可能某处代码执行失败自动抛出(如除以0)
2. 填空:
(1)异常是通过_ 保护 _ 抛出和捕获 _____来实现的。
(2)网站后端程序遇到网络不稳定断连是程序_ 异常_ 误将用户名作为密码进行登录验证是程序_ 错误 _
(3)C++程序中,异常处理的主要任务是_ 处理程序在运行时遇到的问题,尝试回复运行或善后 _
3.假设funcA被调用,则最终将进入哪个catch块,并在处理完后从何处继续执行程序:C
A. ⑤, c处
B. ④, b处
C. ①, a处
D. ①, c处
void funcA()
{
    try
    {
        funcB();
    }
catch (E6 e) {//①}
catch (E7 e) {//②}
// a处
}
void funcB()
{
    try
    {
        funcC();
    }
catch (E4 e) {//③}
catch (E5 e) {//④}
// b处
}
void funcC()
{
    try
    {
        E6 e;
        throw(e);
    }
catch (E1 e) {//⑤}
catch (E2 e) {//⑥}
catch (E3 e) {//⑦}
// c处
}

4.假设funcA被调用,则最终将进入哪个catch块,并在处理完后从何处继续执行程序:B

A. ⑤, c处
B. ④, b处
C. ①, a处
D. ①, c处
void funcA()
{
    try
    {
        funcB();
    }
catch (E6 e) {//①}
catch (E7 e) {//②}
// a处
}
void funcB()
{
    try
    {
        funcC();
    }
catch (E4 e) {//③}
catch (...) {//④}
// b处
}
void funcC()
{
    try
    {
        E6 e;
        throw(e);
    }
catch (E1 e) {//⑤}
catch (E2 e) {//⑥}
catch (E3 e) {//⑦}
// c处
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值