异常(C++)

  • 六、异常
    • [6.1 传统错误处理(如 C语言)](#6.1 传统错误处理(如 C语言))
      • [6.1.1 通过函数返回值处理异常](#6.1.1 通过函数返回值处理异常)
      • [6.1.2 通过远程跳转处理异常](#6.1.2 通过远程跳转处理异常)
    • [6.2 C++的异常处理](#6.2 C++的异常处理)
      • [6.2.1 对传统错误处理的改造](#6.2.1 对传统错误处理的改造)
    • [6.3 函数的异常说明](#6.3 函数的异常说明)
    • [6.4 标准异常类](#6.4 标准异常类)

六、异常

异常是指程序运行期间发生的不正常情况,如 new 无法获得所需内存、数组下标越界、运算溢出、除0错误、无效参数以及打开文件不存在灯。异常处理就是指对程序执行过程中产生的异常进行适当的处理,避免程序出现丢失数据或破坏系统运行等灾难性后果。

6.1 传统错误处理(如 C语言)

6.1.1 通过函数返回值处理异常

cpp 复制代码
#include <iostream>
#include <cstdio>
using namespace std;

class A{
public:
	A(void) {
		cout << "A () " << endl;
	}
	~A(void) {
		cout << "~A ()" << endl;
	}
};

int fun3(){

	FILE* fp = fopen("./1.text", "r");
	if(fp == NULL)
		return -1;

	cout << "open 1.text successed" << endl;
	fclose(fp);

	return 0;
}

int fun2(){
	A b;
	fun3();
}

int fun1(){
	A a;
	fun2();
}
int main (void) {

	A a;

	fun1();
	return 0;
}
//输出结果
myubuntu@ubuntu:~/lv19/cplusplus/dy07$ ./a.out 
A () 
A () 
~A ()
~A ()

优点:函数调用路径中栈对象得到正确析构,不存在内存泄漏

缺点:错误流程处理复杂,代码臃肿

6.1.2 通过远程跳转处理异常

cpp 复制代码
#include <iostream>
#include <cstdio>
#include <csetjmp>
using namespace std;

jmp_buf env;

class A{
public:
	A(void) {
		cout << "A () " << endl;
	}
	~A(void) {
		cout << "~A ()" << endl;
	}
};

int fun3(){

	FILE* fp = fopen("./1.text", "r");
	if(fp == NULL)
		longjmp(env, -1); //跳转到setjmp位置执行

	cout << "open 1.text successed" << endl;
	fclose(fp);

	return 0;
}

int fun2(){
	A b;
	fun3();
}

int fun1(){
	A a;
	fun2();
}
int main (void) {
	
	if(setjmp(env) == 0){ //保存当前栈的快照
		fun1();
	} else {
		return -1;
	}
	return 0;
}
//输出结果
myubuntu@ubuntu:~/lv19/cplusplus/dy07$ ./a.out 
A () 
A ()

优点:不需要逐层判断,一步到位,代码精炼

缺点:函数调用路径中的栈对象失去析构机会,存在内存泄漏风险

6.2 C++的异常处理

对传统错误处理做出了改进:发扬优点,避免缺点。

C++引入了3个用于异常处理的关键字:try, throw, catch。try用于检测可能发生的异常,throw用于抛出异常,catch用于捕获并处理由throw抛出的异常。try-thow-catch构造了C++异常处理的基本结构,形式如下:

cpp 复制代码
try{
    ...
	if err1 throw xx1; //如果是错误1 就抛出xx1异常
	...
	if err2 throw xx2;//如果是错误2 就抛出xx2异常
	...
	if errn throw xxn;//如果是错误n 就抛出xxn异常
}
catch(type1 arg){...}
catch(type2 arg){...}
catch(typen arg){...}

6.2.1 对传统错误处理的改造

cpp 复制代码
#include <iostream>
#include <cstdio>
//#include <csetjmp>
using namespace std;

//jmp_buf env;

class A{
public:
	A(void) {
		cout << "A () " << endl;
	}
	~A(void) {
		cout << "~A ()" << endl;
	}
};

class FileErr{
private:
	string filename;
	int line;
public:
	FileErr(const string& name, int num){
		filename = name;
		line = num;
	}
	friend ostream& operator<<(ostream& os, FileErr& fe);
};

ostream& operator<<(ostream& os, FileErr& fe) {  //输出重载
	os << fe.filename << ": " << fe.line << ": " << "file open failed" << endl;
	return os;
}

int fun3(){

	FILE* fp = fopen("1.text", "r");
	if(fp == NULL) {
		throw FileErr(__FILE__, __LINE__);  //抛出异常
		//throw -1; //抛出异常
	}

	cout << "open 1.text successed" << endl;
	fclose(fp);

	return 0;
}

int fun2(){
	A b;
	fun3();
}

int fun1(){
	A a;
	fun2();
}
int main (void) {
	
	try{
		fun1();
	}
	catch(int err) {
		if(err == -1){
			cout << "handle file open failed" << endl;
			return -1;
		}
	}
	catch(FileErr fe){ //按类类型返回
		cout << fe << endl;
	}
	return 0;
}

注意:catch在进行数据异常类型匹配时,不会进行数据类型的默认转换,只有与异常类型精确匹配的catch块才会被执行。

6.3 函数的异常说明

当一个函数声明中不带任何异常描述时,它可以抛出任何异常。

C++允许限制函数能够抛出的异常类型,限制方法时在函数声明后面添加一个throw参数表,在其中指定函数可以抛出的异常类型。

cpp 复制代码
int fun(int, char) throw(int, char);

函数fun被限定只允许抛出 int 和 char 类型的异常,当 fun 函数抛出其他类型的异常时,程序将被异常终止。

如果函数不允许抛出任何异常,只需要指定throw限制表为不包括任何类型的空表。

cpp 复制代码
int fun(int, char) throw();
cpp 复制代码
#include <iostream>
#include <cstdio>
#include <csetjmp>
using namespace std;

class FileError{};
class MemoryError{};

void func(void) throw(FileError, MemoryError){ //func() 函数里面只能抛出 FileError 和 MemoryError 类型的异常
	//throw FileError();
	//throw MemoryError();
	throw -1; //如果抛别的类型异常   就会终止改程序

}
int main (void) {
	
	try{
		func();
	}
	catch(FileError& er){
		cout << "FileError err" << endl;
	}
	catch(MemoryError& er){
		cout << "MemoryError err" << endl;
	}
	catch(int err){
		cout << "int err" << endl;
	}
	return 0;
}
//输出结果
myubuntu@ubuntu:~/lv19/cplusplus/dy07$ ./a.out 
terminate called after throwing an instance of 'int'
Aborted (core dumped)

6.4 标准异常类

cpp 复制代码
#include <iostream>
#include <cstdio>
#include <csetjmp>
using namespace std;

class FileError : public exception{
public:
	virtual const char * what() const throw(){
		cout << "handle file failed" << endl;
		return "FileError";
	}
};
class MemoryError : public exception{
public:
	virtual const char * what() const throw() {
		cout << "handle memory failed" << endl;
		return "MemoryError";
	}
};

void func(void) throw(FileError, MemoryError){ //func() 函数里面只能抛出 FileError 和 MemoryError 类型的异常
	throw FileError();
	//throw MemoryError();
	//throw -1; //如果抛别的类型异常   就会终止改程序

}
int main (void) {

	try{
		func();
	}
	catch(exception& er){
		/*
		 * 这里就用到多态了,多态通过指针或引用指向的那个对象 就调用那个对象中的成员函数
		 * 这样一改造,就不用写很多的catch捕获函数了 写一个就够了
		 * */
		cout << er.what() << endl;
	}

	return 0;
}
//输出结果
myubuntu@ubuntu:~/lv19/cplusplus/dy07$ ./a.out 
handle file failed
FileError
相关推荐
徐某人..1 小时前
基于i.MX6ULL平台的智能网关系统开发
arm开发·c++·单片机·qt·物联网·学习·arm
无敌秋1 小时前
# C++ 简单工厂模式实战指南
c++·简单工厂模式
淘矿人2 小时前
从0到1:用Claude启动你的第一个项目
开发语言·人工智能·git·python·github·php·pygame
cany10002 小时前
C++ -- 模板的声明和定义
开发语言·c++
澈2072 小时前
深耕进阶 Day1:C 与 C++ 核心差异 + C++ 入门基石
c语言·开发语言·c++
Felven2 小时前
C. Need More Arrays
c语言·开发语言
love530love2 小时前
Podman Machine 虚拟硬盘迁移实战二:用 Junction 把 vhdx 从 C 盘搬到其他盘
c语言·开发语言·人工智能·windows·wsl·podman·podman machine
脱氧核糖核酸__2 小时前
LeetCode热题100——234.回文链表(两种解法)
c++·算法·leetcode·链表
愚者游世2 小时前
noexcept 说明符与 noexcept运算符各版本异同
开发语言·c++·程序人生·面试·visual studio