STL教程3-异常机制

可以跳过直接看总结 

目录

1、基本异常语法

2、异常向上抛,一直到顶层

3、栈解旋

4、异常接口声明

5、抛出异常对象

5、异常类型和异常变量的声明周期

6、异常标准类 

 7、继承在异常中的应用

 8、总结


1、基本异常语法

throw ,然后对应的try.....catch ...

2、异常向上抛,一直到顶层

异常会一层一层的向上抛,如果异常抛到顶层还没有被处理,那么此时程序会使用terminate()去终止程序,c++的异常处理机制是跨函数的。

3、栈解旋

所以throw很类似return,其实就是局部变量离开它的工作空间,会自动的调用析构函数

4、异常接口声明

在函数上声明throw只会抛出指定的数据类型,如果是其他的数据类型会报错。

但是下面在vs2022没有报错


//声明这个函数只会抛出int float char三种类型的异常,抛出其他的就会报错
void func()throw (int, float, char) {
	throw "abc";
}
//不能抛出任何异常
void func02()throw() {
	throw -1;
}

int main() {
	
	try{
		func02(); 
		
	}
	catch (char* str) {
		cout << str << endl;
	}
	catch (int e) {
		cout << "异常" << endl;
	}
	catch (...) {//捕获所有异常
		cout << "未知类型异常" << endl;
	
	}

	
}

5、抛出异常对象

  • throw的异常是有类型的,可以是数字、字符串、类对象
  • throw的异常是有类型的,catch需严格匹配异常类型

 

class MyExcept {
public :
	void what() {
		cout << "抛出一个异常";
	}
};
void func03() {
	throw MyExcept();//抛出了一个匿名对象
}

int main() {
	
	try{
		func03(); 	
	}
	catch (MyExcept e) {
		e.what();
	}
}

 下面是对对象加了点东西

 上面内存泄露了

需要加上析构函数~MyExcept(){if(error!=NULL)delete[]error;}。而且拷贝的时候也会出错

 因此正常代码如下

class MyExcept {
public:
	char* error;
public :
	MyExcept(char* str) {
		error = new char[strlen(str) + 1];
		strcpy(error, str);
	}
	MyExcept(const MyExcept& ex) {
		this->error = new char[strlen(ex.error) + 1];
		strcpy(this->error, ex.error);
	}
	MyExcept& operator=(const MyExcept& ex) {
		if (this->error != NULL) {
			delete[]this->error;
			this->error = NULL;
		}
		this->error = new char[strlen(ex.error) + 1];
		strcpy(this->error, ex.error);
	}
	~MyExcept() { 
		if (error != NULL)
			delete[]error;
	}
	void what() {
		cout << error << endl;
	}
};
void func03() {
	char* str ;
	strcpy(str, "这是一个异常");
	throw MyExcept(str);//抛出了一个异常对象
}

int main() {
	
	try{
		func03(); 	
	}
	catch (MyExcept e) {
		e.what();
	}
}

5、异常类型和异常变量的声明周期

上一个小段的生命周期为

throw的匿名函数会首先调用异常对象的构造函数,然后被catch捕获会调用拷贝函数,

 这里普通元素异常函数处理完成后就会被析构

将上面catch改为引用,引用也是catch处理完成后调用析构函数

 换成指针

 既然不能用匿名函数,那么可以new一个,然后在处理完成后再析构

6、异常标准类 

参考c++标准库异常以及编写自己的异常类的写法_xujianjun229的博客-CSDN博客

 由于标准库的异常是有限的,因此需要编写自己的异常类

但是编写异常类需要注意以下几点

① 建议自己的异常类要继承标准异常类。因为 C++中可以抛出任何类型的异常,所以我们 的异常类可以不继承自标准异常,但是这样可能会导致程序混乱,尤其是当我们多人协同开 发时。

② 当继承标准异常类时,应该重载父类的 what 函数和虚析构函数。

③ 因为栈展开的过程中,要复制异常类型,那么要根据你在类中添加的成员考虑是否提供 自己的复制构造函数

下面是使用标准库异常的例子

这里使用上图的out_of_range,可以看到属于<stdexcept>,因此包含那个头文件

下面写自己的异常类,这个异常类继承于exception

 7、继承在异常中的应用

这里写个能处理各种异常的情况

 注意析构函数必须定义而不能仅仅是声明,因此加上{}

class BaseMyException {
public:
	virtual void what() = 0;
	virtual ~BaseMyException() {};

};
class sourceException:public BaseMyException {
public:
	virtual void what() {
		cout << "目标空间为空" << endl;
	}
	virtual ~sourceException() {}
};
class tagetException :public BaseMyException {
public:
	virtual void what() {
		cout << "目标空间为空" << endl;
	}
	virtual ~tagetException() {}
};



void copy_str(char* taget,const char* source) {
	if (taget == NULL)throw sourceException();
	if (source == NULL)throw tagetException();

	while (*source != '\0') {
		*taget = *source;
		taget++;
		source++;
	}
	*taget = '\0';
}
int main() {
	const char* source = "abncdedf";
	char buf[1024] = { 0 };
	try
	{
		copy_str(NULL, source);
	}
	catch (BaseMyException& e)
	{
		e.what();
	}
	
	cout << buf << endl;

}

 8、总结

1、异常向上抛,一直到顶层,到顶层还不处理会终止程序

2、栈解旋,throw很类似return,函数里进行throw后,函数定义的局部变量会被析构

3、异常接口声明,void func()throw (int, float, char) {...}声明以后,函数里只能抛出这三种异常,但是在windows下貌似不起作用

4、throw的异常是有类型的,可以是数字、字符串、类对象,这个类对象可以是自己写的一个类,比如类里面有个string变量存放消息,throw后使用构造函数给这个变量赋值,然后catch调用打印函数,这个类也可以是继承标准异常类。

5、对于标准库异常类的使用有两种方法,标准库也和第四条一样有一个变量,以out_of_range类为例,第一种是扔出一个out_of_range对象,即throw out_of_range(“这里给变量赋值”);第二种方法是写一个类继承标准库异常类,定义一个存放信息的变量,写自己的构造方法给变量赋值,重写what()方法,重写析构函数,然后catch时用基类统一接收

6、异常处理完成后对象就会被析构,即异常对象的生命周期在catch后结束

7、写各种情况的异常类,这些类继承于一个基类,在catch时只用基类接收就可以

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贪睡的蜗牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值