异常与异常安全

        目录

1、异常简介

(1) 异常的概念

(2) 异常的匹配流程

2、异常安全

(1) 异常安全的几种情况

(2) new和delete之间抛出异常的基本处理思路


1、异常简介

(1) 异常的概念

异常是一种处理错误的方式,当一个函数发现自己无法处理的错误时就可以抛出异常,让函数的直接或间接的调用者处理这个错误。C++异常通常涉及到throw、try、catch 关键字。

  • throw 关键字:抛出关键字
  • try 关键字:划定异常的检查范围
  • catch 关键字:负责捕获 try 块内抛出的异常。“ ... ” 代表任意异常。
void func1() {
	throw "An Exception Is Throwed";	// 抛出一个异常
}

void func2() {
	try							// 检查当前区块中是否有异常抛出
	{
		func1();
	}
	catch (const char* estr)	// 捕获try区块中的异常
	{
		cout << estr << endl;
	}
    catch (...) {				// ... 代表任意异常
		cout << "Unknow Exception" << endl;
	}
}

注意:最后放catch(...) 的原因是,如果异常没有被捕获,程序会直接终止,没有被捕获的原因是抛出异常的类型所有catch语句捕获的异常类型不一致。 

(2) 异常的匹配流程

当一个异常被抛出以后,异常会先检查自己是否处在try关键字的检查范围内

  • 如果不在try 关键字的检查范围内,那就往上一级函数栈查找;
  • 如果在try 关键字的检查范围内,那就查找和异常类型对应的catch语句

这个过程会一直持续,直到main函数栈帧 或者 找到匹配的catch语句。​​​​​​​如果异常被catch语句捕获了,会继续沿着catch子句后面继续执行;如果到达main函数的栈帧,依然没有找到和异常类型匹配的catch语句,程序会直接终止。​​​​​​​​​​​​​​​​​​​​

 注意:func1()后面的 cout 语句不会被执行。一旦发现自己处在try语句的区块以后,会直接跳到catch语句一个个匹配,不会运行try区块中的其他内容

 

2、异常安全

异常可以准确地展示各种错误信息,但是也存在一定缺陷,从上面我们知道,异常确认自己处在try区块以后,会直接跳到catch语句进行匹配,不会执行try区块中的其他语句。

以下面这个图为例,func2() 先动态开辟了一块空间,此时抛出了异常,然后略过delete语句 直接跳转到了catch语句。很显然 动态开辟的空间 p 没有被释放,此时造成了内存泄漏。这是异常安全的一种情况。

(1) 异常安全的几种情况

第一种,构造函数中抛出异常。构造函数负责完成对象的构造和初始化,初始化过程中抛出异常,可能导致对象不完整或没有 完全初始化。

第二种,析构函数中抛出异常。析构函数负责主要完成资源的清理,析构过程中抛出异常可能会导致内存泄漏(动态空间未被释放、句柄未被关闭等)

第三种,new 和 delete、lock 和 unlock 之间抛出异常。不加处理会直接导致内存泄漏(详见上图),后续智能指针会解决这个问题。

(2) new和delete之间抛出异常的基本处理思路

基本思路就是将动态开辟的资源交由一个类SmartPtr来管理,出了try的作用域以后,该类的对象就会被销毁,此时就会调用该类的析构函数,我们可以在析构函数中释放空间

资源管理类的定义如下:

template<class T>
class SmartPtr
{
public:
	SmartPtr(T* ptr) :_ptr(ptr) {}
	~SmartPtr() {
        cout << "delete: " << _ptr << endl; 
		delete _ptr;
        _ptr = nullptr;
	}
private:
	T* _ptr;
};

然后我们修改一下 try 区块中的代码逻辑,sp对象处在try区块的作用域,一旦出了该作用域就会调用SmartPtr 的析构函数。

void func1() {
	throw "An Exception Is Throwed";
}

void func2() {
	try							
	{
		int* p = new int;
		SmartPtr<int> sp(p);	// 交由SmartPtr管理(出了try区块的作用域就会调用析构函数)
		func1();
	}
	catch (const char* estr)	
	{
		cout << estr << endl;
	}
	catch (...) {				
		cout << "Unknow Exception" << endl;
	}
}

测试结果如下,我们发现,资源被释放了,异常也被捕获到了,其实这就是智能指针最基本的原理,借由析构函数来控制资源的释放。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值