<C++>异常

1. 异常处理

throw异常

往上层找catch,如果没找到就报错,找到就直接跳到catch匹配的位置

double Division(int a, int b)
{
	// 当b == 0时抛出异常
	if (b == 0)
		throw "Division by zero condition!";
	else
		return ((double)a / (double)b);
}

void Func()
{

	int len, time;
	cin >> len >> time;
	cout << Division(len, time) << endl;


}
int main()
{
	//Func();
	try
	{
		Func();
	}
	catch (const char* errmsg)
	{
		cout << errmsg << endl;
	}
	catch (int errid)// 其中类型也要匹配,抛char* catch int也会报错
	{
		cout << errid << endl;
	}
	return 0;
}

多个地方有类型匹配的catch,会跳到近的那里(提前捕获)

同一位置不能允许相同的捕获

double Division(int a, int b)
{
	// 当b == 0时抛出异常
	if (b == 0)
		throw "Division by zero condition!";
	else
		return ((double)a / (double)b);
}

void Func()
{
	try
	{
		int len, time;
		cin >> len >> time;
		cout << Division(len, time) << endl;
	}
	catch (const char* errmsg)// 跳到近的这里
	{
		cout << errmsg << endl;
	}
}
int main()
{
	try
	{
		Func();
	}
	catch (const char* errmsg)// 在Func里被捕获了,就不会执行main里的catch
	{
		cout << errmsg << endl;
	}

	return 0;
}

如何一眼看出是什么错误

抛个概率异常

size_t x = 0;// 统计抛异常的次数
// 有25%的概率抛异常
void Probability()
{
	int val = rand();
	if (val<RAND_MAX/4)
	{
		string str = "25%的概率都给你撞上了->";
		str += to_string(val);
		throw str;
	}
	else
	{
		cout << val << endl;
	}
}

void Func()
{
	try
	{
		Probability();
	}
	catch (const string& s)
	{
		++x;
		cout << s << endl;// 接收到的是str的拷贝,str是临时变量,出作用域会被销毁
	}
    catch (...)// 捕获没有匹配的任意类型的异常
	{
		cout << "未知异常" << endl;
	}

}
int main()
{
    srand(time(0));
    for (size_t i = 0; i < 100; i++)// 试100次
    {
    	Func();
    }
    cout << "抛异常的总数:" << x << endl;
	
	return 0;
}

类型匹配的异常能知道是什么错误

可以抛派生类,用基类捕获(可以切片)

定义个exception基类

operator new[]和operator new继承了exception在malloc失败后能抛异常

// exception的子类抛异常
int main()
{
	try
	{
		size_t i = 0;
		while (1)
		{
			int* myarray = new int[1024 * 100];
			cout << myarray << "->" << i++ << endl;
		}
	}
	catch (const exception& ba)
	{
		std::cerr << "bad_alloc caught: " << ba.what() << '\n';
	}

	return 0;
}

2. 异常安全

new了要自己delete

如果中间抛异常,就没法delete,导致内存泄漏,直到资源不足才抛异常(异常安全)

double Division(int a, int b)
{
	// 当b == 0时抛出异常
	if (b == 0)
	{
		throw "Division by zero condition!";
	}
	return (double)a / (double)b;
}

void Func()
{
	// 这里可以看到如果发生除0错误抛出异常,另外下面的array没有得到释放。
	// 所以这里捕获异常后并不处理异常,异常还是交给外面处理,这里捕获了再重新抛出去。

	int* array = nullptr;

	array = new int[1024 * 1024];

	// 异常安全
	try
	{
		int len, time;
		//cin >> len >> time;
		len = rand();
		time = rand() % 5;
		cout << Division(len, time) << endl;
	}
	catch (...)
	{
		// 在这里捕获异常是为了释放空间
		cout << __LINE__ << " delete []" << array << endl;
		delete[] array;
		throw; // 捕获什么抛什么
	}

	cout << __LINE__ << " delete []" << array << endl;
	delete[] array;
}

int main()
{
	srand(time(0));
	while (1)
	{
		try
		{
			Func();
		}
		catch (const char* errmsg)
		{
			cout << errmsg << endl;
		}
		catch (const exception& e)
		{
			cout << e.what() << endl;
		}
	}

	return 0;
}

但这个方法比较low,之后能用智能指针改进它

3. 异常规范

C++98期望每个人写函数,声明是否抛异常,抛什么异常(规范的期待,但不是必须的)

C++11简化了这块规则,如果你不抛异常,你说一声

4. 异常的优缺点

优点

清晰准确

返回错误码要层层返回,异常在哪catch在哪拿到

很多第三方库都包含异常

部分函数使用异常更好处理,比如构造函数没有返回值,不方便使用错误码方式处理。比如T& operator这样的函数,如果pos越界了只能使用异常或者终止程序处理,没办法通过返回值表示错误

缺点

执行流乱跳,很混乱

性能开销

C++没有垃圾回收机制,要用只能指针解决资源管理

C++标准库的异常体系定义得不好(不够全面),导致大家各自定义各自的异常体系,非常的混乱

异常尽量规范使用,否则后果不堪设想,随意抛异常,外层捕获的用户苦不堪言。所以异常规范有两点:一、抛出异常类型都继承自一个基类。二、函数是否抛异常、抛什么异常,都使用 func() throw();的方式规范化。

其他语法,异常机制基本差不多

C++独有缺陷:

标准库定义不好用。不支持看堆栈

C++没有垃圾回收器,所以申请内存和释放内存位置要很小心。容易泄露,需要RAII机制再补充

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

天影云光

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

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

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

打赏作者

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

抵扣说明:

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

余额充值