C/C++基础(自用)—异常

异常的基本概念

遇到错误 抛出异常 捕获异常

异常:是指在程序运行的过程中发生的一些问题(如:除0溢出,数组下标越界,要读取的文件不存在,空指针,内存不足,访问非法内存等)。
异常是一个类
异常处理不适用于处理异步事件相关的错误的:磁盘去写结束、网络信息到达等
异常处理机制还适用于处理程序与其他软件元素:成员函数、构造函数、析构函数、类交互时出现的问题。

C++异常机制与C语言异常处理的优势:
1.函数的返回值可以忽略,但异常不可以忽略。(忽略异常,程序结束)
2.整型返回值没有任何语义信息。而异常却包含语义信息,有时从类名就可以体现出来

基本思想

在这里插入图片描述

异常的抛出与捕获

异常的抛出捕获

try
{ //抛出异常,可能是一小段代码,更可能的是调用别的函数
	throw 异常值;
} 
catch(异常类型1 异常值1)  //捕获异常
{
	处理异常的代码1;
}
catch(异常类型2 异常值2)
{
	处理异常的代码2;
}
catch(...)//捕获所有异常
{
	处理异常的代码3;
}

如果匹配的处理器没有被找到,则库函数ternubate将会被自动调用,其默认是调用abort来终止程序

案例

#include<iostream>
using namespace std;

int divide(int x, int y) {
	if (y == 0)
		throw x;
	return x / y;
}
int main() {
	try
	{
		cout << "5/2=" << divide(5, 2) << endl;
		cout << "8/0=" << divide(8, 0) << endl;
		cout << "7/1=" << divide(7, 1) << endl;
	}
	catch (int e)
	{
		cout << e << "is divide by zero!" << endl;
	}
	cout << "That is ok." << endl;
	return 0;
}

在这里插入图片描述
第一次调用时为divide(5,2)调用正确,第二次调用时为divide(8,0),从发生异常的这一点之后都不会执行了,所以直接跳到throw x; 之后又跳到catch(int e)继续执行

栈解旋

异常被抛出后,从进入try块起,到异常被抛弃前,这期间在线上构造的所有对象,都会被自动析构。析构的顺序与构造的顺序相反,这一过程称为栈的解旋。

案例

#include<iostream>
using namespace std;

class Data
{
public:
	Data(){}
	Data(int a)
	{
		this->a = a;
		cout << "构造函数" << a << endl;
	}
	~Data() {
		cout << "析构函数" << a << endl;
	}

private:
	int a;
};

int main()
{
	int ret = 0;
	try
	{
		Data ob1(10);
		Data ob2(20);
		Data ob3(30);
		throw 1;
	}
	catch (int)//捕获
	{
		cout << "int的异常值:" << endl;
	}
	catch (char)//捕获
	{
		cout << "char的异常值:" << endl;
	}
	catch (...)//捕获
	{
		cout << "其他异常值" << endl;
	}
}

先构造 后析构结束时候再捕获异常,这个过程叫做栈解旋
在这里插入图片描述

异常声明(异常规范)

一个函数显式地声明可能抛出的异常,有利于函数的调用者为异常做好准备

函数默认:可以抛出任何类型的异常

void fun01()
{
	//throw 1;
	//throw '1';
	throw "hello";
}

只能抛出特定类型异常

void fun02()throw(int,char)
{
	//throw 1;
	//throw '1';
	throw "hello"; //抛出,不能捕获 只能捕获int,char类型
}

不抛出任何异常

void fun01()throw() //或void fun01() noexcept;
{
	throw 1;
	//throw '1';
	//throw "hello";
}
  • 对于明确不抛出异常的函数,C++推荐使用noexcept说明修饰
  • 方式:返回值类型func(形参列表) noexcept;
    • 异常处理使编译和运行时都有额外的开销,省去异常处理可优化加速调用
    • 需爆出该函数内部调用函数和定义语句均不会抛出异常的一致性
  • 配套有noexcept运算符,可以判断函数是否使用了noexcept说明
void f() noexcept;
noexcept(f());//返回true,因为f有noexcept说明

异常处理中的构造与析构

自动的析构

  • 找到一个匹配的catch异常处理后
    • 初始化异常参数
    • 将从对应的try块开始到异常被抛掷处之间构造(且尚未析构)的所有自动对象进行析构
    • 从最后一个catch处理之后开始恢复执行。
#include<iostream>
#include<string>
using namespace std;

class MyException {
public:
	MyException(const string &message):message(message){}
	~MyException() {}
	const string &getMessage() const { return message; }
private:
	string message;
};

class Demo {
public:
	Demo() { cout << "Constructor of Demo" << endl; }
	~Demo()
	{
		cout << "Destructor of Demo" << endl;
	}
};

void func() throw(MyException) {
	Demo d;
	cout << "Throw MyException is func()" << endl;
	throw MyException("exception thrown by func()");
}
int main() {
	cout << "in main function" << endl;
	try
	{
		func();
	}
	catch (MyException& e)
	{
		cout << "Caught an exception:" << e.getMessage() << endl;
	}
	cout << "Resume the execution of main()" << endl;
	return 0;
}

在这里插入图片描述

C++标准异常

在这里插入图片描述

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值