【c++】异常

程序有时会遇到运行阶段的错误,比如打开一个不存在的文件,请求过多内存,接受一个不能使用值……通常程序员会避免这样的的以外,而c++提供了一种功能强大的而灵活的工具——异常。

例如下面这个示例

int main(int argc, char** argv) {
	int x=19;
	int y=-x;
	std::cout<<(2*x*y/(x+y));/分母不能为0
	return 0;
}

上面是输出两个数的调和平均数(两个数的倒数的平均数的倒数)

对于上面程序而言编译器可能输出一个表示无穷大的浮点数值,cout将这个值输出为Inf,inf,INF(Infinitely),也可能直接崩溃。这取决你的编译器,而我用的g++直接奔溃了

解决方法 1:

#include <iostream>
#include<cstdlib>//for abort()
using std::cout;
using std::cin;
using std::endl;
double harmonic(double a,double b);

int main(int argc, char** argv) {
	int x=0;
	int y=0;
	cout<<"enter two number";
	while(cin>>x>>y)
	{
		int z=harmonic(x,y);
		cout<<"harmonic mean of "<<x
		<<" and "<<y<<" is "<<z<<endl;
		cout<<"enter next set of number<q to quit>:";
		 
	}
	cout<<"Bye!\n";
	
	return 0;
}
double harmonic(double a,double b){
	if(a==-b){
		cout<<"untenable argument to harmonic\n";
		std::abort(); 
	}
	return 2.0*a*b/(a+b);
}

abort 是位于头文件cstdlib 中,其典型实现是向标准错误流发送
abnormal program termination(程序终止)然后终止程序,还返回一个随实现而异的值,告诉父进程处理失败。abort刷不刷新文件缓冲区(用于存储读写到文件中的数据的内存区域)取决于实现。也可以用exit()它会刷新缓冲文件缓冲区,但不显示消息

解决方法 2

一种比异常终止更灵活的方法是,使用函数返回值来指出问题。例如ostream类的get(void)函数通常返回下一个输入的字符的ASCII吗。但都到文件尾部时返回特殊的EOF(一般为signed char)。对haemonic()来说这种方式不管用,因为任何数值都是有效的返回值(答案)这时候我们就可以使用指针或者引用充当返回值。并使用函数返回值来指定返回的的成功和失败

#include <iostream>
#include<cfloat>//for DBL_MAX

using std::cout;
using std::cin;
using std::endl;
bool harmonic(double ,double ,double* );

int main(int argc, char** argv) {
	
	double x,y,z;
	cout<<"enter two number";
	while(cin>>x>>y)
	{	
	

		if(harmonic(x,y,&z))	
			cout<<"harmonic mean of "<<x
			<<" and "<<y<<" is "<<z<<endl;
		else
			cout<<"one value should not be the negative"
				<<"of the ohter ,try again\n";
		
		cout<<"enter next set of number<q to quit>:";
		 
	}
	cout<<"Bye!\n";
	
	return 0;
}
bool harmonic(double a,double b,double* ans){
	if(a==-b){
		*ans=DBL_MAX;
		return false;
	}
	else{
		
		* ans=2.0*a*b/(a+b);
		
		return true;
		
	}
	
}

解决方法 3

#include <iostream>
#include<cfloat>//for DBL_MAX

using std::cout;
using std::cin;
using std::endl;
double harmonic(double ,double );

int main(int argc, char** argv) {
	
	double x,y,z;
	cout<<"enter two number";
	while(cin>>x>>y)
	{	

	try{
		z=harmonic(x,y);
	}catch(const char * s){
		cout<<s<<endl;
		cout<<"Enter a new  pair of number";
		continue;
	}
	cout<<"harmonic mean of "<<x
		<<" and "<<y<<" is "<<z<<endl;	
	cout<<"enter next set of number<q to quit>:";
		 
	}
	cout<<"Bye!\n";
	
	return 0;
}
double harmonic(double a,double b){

	if(a==-b){
		throw "bad harmonic() arguments :a =-b not allowed";
	}		
	return 2.0*a*b/(a+b);
		
	
}

异常的格式如下

try{
	//抛出异常的语句
}catch(exceptionType exceptionParameter){
	//异常怎么处理写在这
}

就像上面的示例那样throw在try中抛出了一个错误,错误类型是一串字符。try接受到错误,然后程序跳转到catch语句块。其中exceptionType 为我们throw抛出的参数类型。exceptionParameter是参数的名称,我们可以在catch语句块中使用这个参数。

将对象用作异常类型

#include <iostream>
#include<cmath>//for sqrt()

using std::cout;
using std::cin;
using std::endl;


class bad_hmean
{
	private:
		double v1;
		double v2;
	public :
		bad_hmean(double  a=0,double b=0):v1(a),v2(b){};
		void mesg();
		
};
inline void bad_hmean::mesg(){
	cout<<"hmean("<<v1<<","<<v2<<")"
		<<"incalid argument: a=-b"<<endl;
	
}
class bad_gmean{
	public:
		double v1;
		double v2;
		bad_gmean(double a=0,double b=0):v1(a),v2(b){}
		const char* mesg();
};
inline const char* bad_gmean::mesg(){
	return "gmean() arguments should be>=0\n";
	
}
double hmean(double a,double b);
double gmean(double a,double b);


int main(int argc, char** argv) {
	
	double x,y,z;
	cout<<"enter two number";
	while(cin>>x>>y)
	{	

	try{
		z=hmean(x,y);
		cout<<"Harmonic mean of "<<x<<"and"<<y
			<<"is"<<z<<endl;
		
		cout<<"Geometric mean of "<<x<<"and"<<y
			<<"is"<<gmean(x,y)<<endl;
	}catch(bad_hmean & bg){
		bg.mesg();
		cout<<"try again";
		continue;
	}catch(bad_gmean& hg){
		cout<<hg.mesg();
		cout<<"Value used:"<<hg.v1<<","<<hg.v2<<endl;
		cout<<"Sorry ,you don't get to play any more.\n";
		break;
	}
	cout<<"Bye!\n";
	
	return 0;	
	}
}
double hmean(double a,double b){

	if(a==-b){
		throw bad_hmean(a,b); 
	}		
	return 2.0*a*b/(a+b);
		
	
}
double gmean(double a,double b){

	if(a<0||b<0){
		throw bad_gmean(a,b)
 
	}		
	return std::sqrt(a*b);
		
	
}

上面代码使用了对象作为throw 的返回类型,且使用多个catch语句块

异常规范和c++11

异常规范是告诉编译器一个函数师是否可能会产生异常,格式如下

int fun1()thow(bad_thing);//可能产生异常
int fun2()thow();
//不会产生异常

上述格式可以出现在函数声明定义上,这是c++98引入的概念,但是c++11已经摒弃这种做法了。这样函数之间的调用会加大编译器的检查难度。其次如果我们更新了代码库,而以前的代码如果不修改可能会无法使用。

所以建议不要使用上述异常规范
c++11引用了noexcept来指出函数不产生异常

int main() noexcept

还有运算符 noexcept(OperandName)用来判断操作数是否会引发异常

异常的重要特性

引发异常时编译器总会创建一个临时拷贝,即使异常规范和catch中指定时引用,我们会这样呢。请款下面例子:

class problem{};
……
void super()(problem)
{
……
	if(oh_no)
	{
		problemoops;
		throw oops;
	}
……
}

……
try{
	super();
}catch(problem & p){
//……
}

上面的oops在函数执行完就没了,所以必须拷贝一个临时变量。
既然会创建临时变量为什么要用引用呢。毕竟引用作为返回值就是节省创建副本的开销啊。这是因为因为基类的引用可以使用派生类的方法。当有一系列的异常层次结构时。这是后基类的异常类型引用将匹配所有派生类的异常。这就需要注意一点就是catch的顺序了

class bad_1{};
class bad_2:public bad_1{};
class bad_3:public bad_2{};
……
try{
}catch(bad_3){
}catch(bad_2){
}catch(bad_1){
}

上面的catch语句开顺序是呵护清理的,因为bad_1是基类如果放在第一个catch中的话,抛出的所有异常都会有bad_1语句块处理,根本没有后面的catch{}什么事。

#…#
当我们调用一个函数时,我们可能不知道这个函数会抛出什么异常。但是我们也可以捕获异常。就是使用…

try{
	fun()
}catch(...){
	cout<<"have exception";
}

#.#

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值