要点
- 异常根据抛出的类型捕获,可以直接捕获接收或通过引用接收。但二者同时只能存在一个。
- 栈内存创建的对象指针抛出后会产生野指针问题
- 动态创建对象的指针抛出后可以正常捕获使用,但是需要手动释放。
- 函数声明可以加上异常声明。限制函数可以抛出的异常类型。
- 异常有栈解锁机制,栈内存中创建的对象在异常抛出后会自动析构。
- 异常可以捕获并继续向上抛出。
示例代码
#include "stdafx.h"
#include "iostream"
#include "string.h"
using namespace std;
#pragma warning(disable : 4996)
class ExceptionA {
private:
char *msg;
public:
ExceptionA(const char *msg) {
cout << "构造" <<msg<< endl;
if (msg == NULL) {
this->msg = NULL;
}else{
this->msg = new char[strlen(msg) + 1];
strcpy(this->msg, msg);
}
}
char * getMsg()const {
return this->msg;
}
ExceptionA(const ExceptionA& e) {
cout << "拷贝构造" << endl;
if (this->msg == NULL) {
delete[]this->msg;
}
this->msg = new char[strlen(e.getMsg()) + 1];
strcpy(this->msg, e.getMsg());
}
~ExceptionA() {
cout << "析构" << msg << endl;
if (this->msg != NULL) {
delete[]this->msg;
}
}
};
void funcA(int x) {
switch (x)
{
case 0:{
//throw异常后,temp1会自动析构,而temp不会自动析构和释放
ExceptionA *temp = new ExceptionA("temp");
ExceptionA temp1("temp1");
throw 1;
}
break;
case 1:
throw 'a';
break;
case 2:
//可以直接接受或使用引用接收。推荐使用引用接收
throw(ExceptionA("msg 2"));
break;
case 3:
//抛出指针,但对象会被清理。catch到的指针是野指针
throw(&ExceptionA("msg 3"));
break;
case 4: {
//抛出动态分配的指针。catch到后使用完后需要delete
ExceptionA* e = new ExceptionA("msg4");
throw(e);
}
break;
case 5:
throw 3.14f;
case 6:
throw 3.14;
}
cout << "funcA success " << x << endl;
}
void funcB(int index) throw(float ,double){
try {
funcA(index);
}
catch (int e) {
cout << "catch int " << e << endl;
}
catch (char e) {
cout << "catch char " << e << endl;
}
catch (ExceptionA e) {
cout << "catch ExceptionA " << e.getMsg() << endl;
}
//使用对象接收和使用对象的引用接收不能同时存在。
//catch (ExceptionA &e) {
// cout << "catch ExceptionA & " << e.getMsg() << endl;
//}
catch (ExceptionA *e) {
cout << "catch ExceptionA * " << e->getMsg() << endl;
delete e;
}
catch (float e) {
//接续向上抛出异常
cout << "catch float and throw " << e << endl;
throw e;
}
catch (double e) {
//接续向上抛出异常,但函数的方法上有限制可以抛出异常的类型。这里会出错
cout << "catch double and throw " << e << endl;
throw e;
}
}
int main()
{
try {
funcB(6);
}
catch (float e) {
cout << "main catch " << e << endl;
}
return 0;
}
异常处理场景演示
-
funcB(0)
0.png
这里创建了两个对象一个在堆中动态创建temp.一个在栈中temp1。执行结果看到temp1自动被析构,而temp未被析构。c++在异常抛出后有栈解锁机制,会自动析构在栈中创建的对象。
-
funcB(1)
1.png
这里就是按类型在funcA中正常的catch
-
funcB(2) 栈内存对象
-
用对象直接接收
2.png
这里看到当抛出对象时候,catch中接受时类似方法实参到形参的传递,进行拷贝构造。
-
用对象的引用接收
7.png
catch中得到对象的引用。
-
-
funcB(3) 抛出栈内存对象的指针
3
catch得到对象的指针前。对象已被析构,这里得到的就是野指针。
-
funcB(4) 动态创建对象
4.png
可以正常catch到并使用。但使用完后需要手动释放。
-
funcB(5) 捕获到异常后继续向上抛出
5.png
funcA中继续抛出,在main中正常捕获。
-
funcB(6) 方法异常类型声明
6.png
限制方法能够抛出异常的类型,如果不在范围内,运行会报错
网友评论