C++异常处理

本文详细探讨了C++异常处理机制如何提高代码可读性和错误处理效率,包括异常的优点(如直观的错误信息传递和栈展开),异常引发与捕获的示例,以及自定义异常类的使用。重点讲解了异常接口声明、多态和标准库异常类的应用。
摘要由CSDN通过智能技术生成

1. C语言异常处理:

  1. 使用整形的返回值标识错误。
  2. 使用errno宏记录错误。

缺陷:
1.有些函数返回1成功,有些返回0成功,有些需要判断指针为 NULL.显得混乱
2.函数的返回值返回错误代码不能携带其他信息(可通过指针)

2.C++

1 .异常处理机制的优势:(可能Java python也一样)
  1. 函数返回值可以忽略,异常不可以。当出现异常,没有用被程序捕获时,程序就会终止。
  2. 异常可以包含语义信息,如异常类名。更直观
  3. 异常是一个类,其成员可以传递大量信息。
  4. 异常处理可以在调用跳级。这是一个代码编写时的问题:假设在有多个函数的调用栈中出现了某个错误,使用整型返回码要求你在每一级函数中都要进行处理。而使用异常处理的栈展开机制,只需要在一处进行处理就可以了,不需要每级函数都处理。
int division(int a,int b)
{
	if (b == 0){
		return -1;
	}
	return a / b;
}
2.引发

当隔代多次调用此函数,由于原函数没有异常处理,导致调用者也无法捕获异常。应该是原函数和调用都可以捕获异常,当自己不处理的时候可以让(抛)上次处理。
修改代码:

int division(int a,int b)
{
	if (b == 0){
		throw 0;
	}
	return a / b;
}
当A在调用时://由于没有处理异常,程序直接中断执行
int A_tets(int a,int b){
	return ret = division(a,b) + 100; //当b为0 
}
当B在调用时,
int B_test()
{
	int a = 10;
	int b = 0;
	int ret = 0;
	try{
		ret = A_test(a,b);
		//此时由于A_test没有抛出异常,导致当前函数捕获不了异常
	}
	catch(int e){
		cout<<"一个数除以了:"<< e<<endl;
	}
	return ret;
}
3.总结
  • 若有异常则通过throw操作创建一个异常对象并抛出。
  • 将可能抛出异常的程序段放到try块之中。
  • 如果在try段执行期间没有引起异常,那么跟在try后面的catch字句就不会执行。
  • catch子句会根据出现的先后顺序被检查,匹配的catch语句捕获并处理异常(或继续抛出异常)
  • 如果匹配的处理未找到,则运行函数terminate将自动被调用,其缺省功能调用abort终止程序。
  • 处理不了的异常,可以在catch的最后一个分支,使用throw,向上抛。

c++异常处理使得异常的引发和异常的处理不必在一个函数中,这样底层的函数可以着重解决具体问题,而不必过多的考虑异常的处理。上层调用者可以在适当的位置设计对不同类型异常的处理。

4.捕获方式:
通过异常严格类型匹配,但是与函数匹配机制互不相关。
当	threw 10:threw 'a':threw "ssssss";threw string("ex");  -->
	try{
		test_threw();
		//根据threw的数据类型执行对应的catch()
	}
	catch (int){
		cout << "抛出Int类型异常!" << endl;
	}
	catch (char a){
		cout << "抛出char类型异常!" << endl;
	}
	catch (char *){
		cout << "抛出char*类型异常!" << endl;
	}
	catch (std::string){
		cout << "抛出std::string类型异常!" << endl;
	}
5. 当抛出异常时会发生栈解旋:
异常被抛出后,从进入try块起,到异常被抛掷前,
这期间在栈上构造的所有对象,都会被自动析构。
析构的顺序与构造的顺序相反,这一过程称为栈的解旋(unwinding).
void Testthrew()
	obj o1("aaa");
	obj o2("bbb");
	obj o3("ccc");
	//抛出异常
	string ex = "error";
	throw ex;
}
ccc----析构
bbb----析构
aaa----析构
6.异常接口声明
  • 为了加强程序的可读性,可以在函数声明中列出可能抛出异常的所有类型,例如:void func()throw(A,B,C);这个函数func能够且只能抛出类型A,B,C及其子类型异常
  • 如果在函数声明中没有包含异常接口声明,则此函数可以抛任何类型的异常,例如:void func()
  • 一个不抛任何类型异常的函数可声明为:void func() throw()
  • 如果一个函数抛出了它的异常接口声明所不允许抛出的异常,unexcepted函数会被调用,该函数默认行为调用terminate函数中断程序。
//可以抛出所有类型异常
void test_throw(){
	...
	throw ‘a';
}
//可以抛出指定类型异常
void test_throw() throw(int ,char,char*,std::string)
{
	...
	string exception = "error!";
	throw exception;
}
//不允许
void test_throw() throw()
{
	...
	string exception = "error!";
	throw exception;
	unexcepted函数会被调用,该函数默认行为
	调用terminate函数中断程序。
}
7. 异常变量生命周期
  • throw的异常是有类型的,可以是数字、字符串、类对象。
  • throw的异常是有类型的,catch需严格匹配异常类型。
class MyException
{
public:
	MyException() {
		cout << "异常变量构造" << endl;
	};
	MyException(const MyException & e){
		cout << "拷贝构造" << endl;
	}
	~MyException(){
		cout << "异常变量析构" << endl;
	}
};
void test_throw()
{
	throw new MyException(); //test1 2都用 throw MyExecption();
}
void test01()
{
	try{
		test_throw();
	}
	catch (MyException e){
		cout << "捕获 异常" << endl;
	}
}
void test02()
{
	try{
		DoWork();
	}
	catch (MyException &e){
		cout << "捕获 异常" << endl;
	}
}

void test03()
{
	try{
		DoWork();
	}
	catch (MyException *e){
		cout << "捕获 异常" << endl;
		delete e;
	}
}
前两个报错执行终止
terminate called after throwing an instance of 'MyException*'
Aborted (core dumped)
第三个正常
8.异常的多态
//异常基类
class BaseException{
public:
	virtual void printError(){};
};

//空指针异常
class NullPointerException : public BaseException{
public:
	virtual void printError(){
		cout << "空指针异常!" << endl;
	}
};
//越界异常
class OutOfRangeException : public BaseException{
public:
	virtual void printError(){
		cout << "越界异常!" << endl;
	}
};

void doWork(){

	throw NullPointerException();
}

void test()
{
	try{
		doWork();
	}
	catch (BaseException& ex){
		ex.printError();
		delete ex;
	}
}
9. 标准库中的异常类:

在这里插入图片描述
标准异常类的成员:
① 在上述继承体系中,每个类都有提供了构造函数、复制构造函数、和赋值操作符重载。
② logic_error类及其子类、runtime_error类及其子类,它们的构造函数是接受一个string类型的形式参数,用于异常信息的描述
③ 所有的异常类都有一个what()方法,返回const char* 类型(C风格字符串)的值,描述异常信息。

#include<stdexcept>
class Person{
public:
	Person(int age){
		if (age < 0 || age > 150){
			throw out_of_range("年龄应该在0-150岁之间!");
		}
	}
public:
	int mAge;
};

int main(){
	try{
		Person p(151);
	}
	catch (out_of_range& ex){
			cout << ex.what() << endl;
	}
}
10.自定义异常类:

继承标准异常,应该重载父类的what函数和虚析构函数。因为栈展开的过程中,要复制异常类型,那么要根据你在类中添加的成员考虑是否提供自己的复制构造函数。

//自定义异常类
class MyOutOfRange:public exception
{
public:
	MyOutOfRange(const string  errorInfo)
	{
		this->m_Error = errorInfo;
	}

	MyOutOfRange(const char * errorInfo)
	{
		this->m_Error = string( errorInfo);
	}

	virtual  ~MyOutOfRange()
	{
	
	}
	virtual const char *  what() const
	{
		return this->m_Error.c_str() ;
	}

	string m_Error;

};

class Person
{
public:
	Person(int age)
	{
		if (age <= 0 || age > 150)
		{
			//抛出异常 越界
			//cout << "越界" << endl;
			//throw  out_of_range("年龄必须在0~150之间");

			//throw length_error("长度异常");
			throw MyOutOfRange(("我的异常 年龄必须在0~150之间"));
		}
		else
		{
			this->m_Age = age;
		}
		
	}

	int m_Age;
};


void test01()
{
	try
	{
		Person p(151);
	}
	catch ( out_of_range & e )
	{
		cout << e.what() << endl;
	}
	catch (length_error & e)
	{
		cout << e.what() << endl;
	}
	catch (MyOutOfRange e)
	{
		cout << e.what() << endl;
	}
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值