目录
c++异常与c传统处理错误的区别
c语言处理错误的方式
c++处理错误的方式
异常的抛出和处理
demo
异常的重新抛出
demo
异常安全
noexcept
自定义异常体系
c++舍弃了c语言处理错误的方式,引入了异常来处理错误。
c++异常与c传统处理错误的区别
c语言处理错误的方式
1.暴力的终止程序,如assert终止程序。
2.返回错误码。
c++处理错误的方式
1.触发异常,将异常抛出。
2.捕捉异常,执行异常处理。
相比c语言,c++的处理更柔和,出错了程序也会照常执行,但是执行流会直接跳转到,异常处理的代码块。
异常的抛出和处理
throw:抛出异常,异常可以是任意的类型。
try:捕捉try代码块内抛出的异常。
catch:代码块内是处理异常的,catch() 括号内是捕捉异常的类型。
注意:
1.异常捕捉的规则是最近,匹配的catch。
2.异常如果到了main函数中还没有被捕获,程序就会直接终止。
3.通常会在最后加上catch(...),catch(...)可以捕获任意异常,这个主要就是增强代码的健壮性,防止,漏捕获异常,导致程序终止。
4.当异常出发throw之后的代码不会在继续执行,执行流跳转到,与抛出类型相同最近的catch代码块。
demo
简单的除零错误
#include<iostream>
using namespace std;double Division(int a, int b)
{// 当b == 0时抛出异常if (b == 0){throw "Division by zero condition!";//抛出了一个cosnt char*的异常cout << "~~~~~~~~~~~~~~" << endl;}elsereturn ((double)a / (double)b);
}int main()
{try {Division(1,2);Division(1,0);}catch (const char * message)//这个catch只能捕捉const char*的异常{cout << message << endl;}catch (...)//捕捉任意的异常{cout<<"unknown execption" << endl;}cout << "-------------------" << endl;return 0;
}
异常的重新抛出
当异常抛出的时候,执行流回跳转,这时候就出现一个问题,在抛出异常之前动态开辟了一块空间,但是我这块空间还没来得及释放,但是执行流已经跳走了,这就会导致资源的泄露。
这种情况需要将异常处理之后,重新抛出,更好的办法就是使用智能指针,使用对象管理资源。
demo
#include<iostream>
using namespace std;double Division(int a, int b)
{// 当b == 0时抛出异常if (b == 0){throw "Division by zero condition!";cout << "~~~~~~~~~~~~~~" << endl; //没有被打印}elsereturn ((double)a / (double)b);
}void Func()
{int* arry = new int[5];try{int len, time;cin >> len >> time;cout << Division(len, time) << endl;}catch (...){delete[] arry;cout << "already delete" << endl;throw;}delete[] arry;
}int main()
{try{Func();}catch (const char * message){cout << message << endl;}catch (...){cout<<"unknown execption" << endl;}//cout << "-------------------" << endl;return 0;
}
异常安全
有一些的函数是不可以抛异常的,就像构造函数和析构函数。
构造函数通常用来初始化对象,如果初始化到一半,抛异常执行流跳走,会产生一个只初始化一半的怪物,会引起更多的异常。
构造函数通常用来清理资源,如果抛异常执行流跳走,会导致有的资源未被释放,导致资源泄露。
noexcept
由noexcept 修饰的函数,不会抛出异常。
自定义异常体系
在实际开发中,都会有一个异常的体系,因为如果异常是随便抛出的,那可就坏事了,程序员A抛出了一个int,程序员B抛出了一个char*。
异常是不能随便抛的,是要有严格规范的。
通常都会使用多态,catch基类可以捕捉抛出的派生类的异常。
使用基类调用,what这个虚函数。
class Exception
{
public:Exception(const string& errmsg, int id):_errmsg(errmsg),_id(id){}virtual string what() const{return _errmsg;}protected:string _errmsg;int _id;
};class SqlException : public Exception
{
public:SqlException(const string& errmsg, int id, const string& sql):Exception(errmsg, id), _sql(sql){}virtual string what() const{string str = "SqlException:";str += _errmsg;str += "->";str += _sql;return str;}private:const string _sql;
};