目录
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;
}
else
return ((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; //没有被打印
}
else
return ((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;
};