C++异常处理机制

一、C++异常:

语法错误(编译错误):

比如变量未定义、括号不匹配、关键字拼写错误等等编译器在编译时能发现的错误,这类错误可以及时被编译器发现,而且可以及时知道出错的位置及原因,方便改正。

运行时错误:

比如数组下标越界、系统内存不足等等。这类错误不易被程序员发现,它能通过编译且能进入运行,但运行时会出错,导致程序崩溃。

如我们进程使用一些垃圾软件会闪退,这就是因为他门的程序异常没有处理好,所以遇到预测范围外的错误时,程序就会直接终止。

所以为了解决这种情况,在C++里面就提出了异常处理机制,当一个函数无法处理产生的错误时,就抛出异常,让函数的调用者直接或者间接处理从错误。

二、异常处理的优缺点:

优点:
1.可以清晰的展示出错误原因,不像返回错误码那么模糊
2.许多第三方库使用异常,因此容易与这些结合使用
3.在测试框架里使用比较方便

缺点:
1.会打断执行流,函数有可能不在该返回的地方返回,这样使得代码的管理和调试困难
2.异常安全加大了代码量,需要大量的支持。

三、C++异常处理机制:

代码环境:VS2010

1.异常语法格式

在C++中,异常的抛出和处理主要使用了以下三个关键字:try、 throw 、 catch.其格式如下:
当我们在程序中想抛出一个异常时,可以这样:

#include<iostream>
#include<exception>
using namespace std;

//使用异常处理
int Div(int left,int right){
    if(right==0){
        throw exception("除数不能为0");
    }
    return left/right;
}

//未使用异常处理
int UnDiv(int left,int right){
    return left/right;
}

当我们想使用这个函数时,需要在函数外部进行异常的捕获:

int main(){
    try{
        Div(10,20); //合法
        Div(10,30); //合法
        Div(10,0);  //非法,会抛出异常
    }catch(exception & e){
        cerr<<e.what()<<endl;   //打印异常信息
    }
    return 0;
}

输出结果:
Alt

未加入异常处理时:

int main(){
        UnDiv(10,20); //合法
        UnDiv(10,30); //合法
        UnDiv(10,0);  //非法,程序奔溃
    return 0;
}

输出结果:程序崩溃
在这里插入图片描述

2.异常处理流程:

a).异常抛出

下面的例子中,通过throw抛出了一个异常类的实例,这个异常类,可以是任何一个自定义的类,通过实例化传入的参数可以表明发生的错误信息。其实异常就是一个带有异常信息的类而已。

class MyError { 
	const char* const data; 
	public: 
	MyError(const char* const msg = 0):data(msg) 
	{ 
	 //idle 
	} 
}; 

    
void do_error() { 
	throw MyError("something bad happend"); 
} 



int main() 
{ 
	do_error(); 
} 

b).异常捕获

C++中通过catch关键字来捕获异常,捕获异常后可以对异常进行处理,这个处理的语句块称为异常处理器。下面是一个简单的捕获异常的例子:

 try{ 
		//do something 
		int left = 5;
		int right = 0;
		left/right;
		throw string("this is exception"); 
	}
	catch(const string& e) { 
		cout << "catch a exception " << e << endl; 
} 

c).异常匹配

使用自定义的类来异常抛出;

class Base{ 
public: 
	Base(string msg):m_msg(msg) { 
	} 
	virtual void what(){ 
		cout << m_msg << endl; 
	} 
	void test() { 
		cout << "I am a CBase" << endl; 
	} 
	protected: 
	string m_msg; 
}; 

//派生类,重新实现了虚函数 
class CBase : public Base 
{ 
public: 
	CBase(string msg):Base(msg) {     
	} 
	void what() { 
		cout << "CBase:" << m_msg << endl; 
	} 
}; 

int main() 
{ 
	try { 
		//do some thing ,like
		int left = 5;
		int right = 0;
		left/right;
		//抛出派生类对象 
		throw CBase("I am a CBase exception"); 
	}
	catch(Base& e) {  //使用基类可以接收 
		e.what(); 
	} 
	getchar();
	return 0;
} 

输出结果:
在这里插入图片描述

四、C++异常处理注意的地方

  • 1.代码中抛出异常对象后,会在函数调用链里与该对象类型匹配且离抛出异常处最近的catch匹配(就近原则)。

  • 2.异常抛出后,会打乱程序执行流,会释放局部存储对象,因此在调试含异常的代码比较难调试。

  • 3.异常抛出的类型必须和catch捕捉的类型必须匹配才可捕获,只有以下三种情况例外:

  • 允许非const对象到const对象的转换

    • 允许派生类到基类的转换,这一点很重要,因为库里的exception就用到了这条原理。
    • 将数组转换为指向数组的指针,将函数转换为指向函数的指针。
  • 4.(异常的再次抛出)catch可以将收到的异常处理后再次抛给外层调用链,再由外层catch进一步处理。

  • 5.记住!不要在析构函数里和构造函数里抛异常。分别可能会导致对象数据清理不完全,造成内存泄漏。可能会造成对象初始化不完全,在别人使用时可能调用野指针。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值