目录
一.异常
1.1C++异常概念
1.2异常的使用
1.3异常和栈帧,重新抛出
二.异常体系
2.1自定义异常体系
2.2C++标准库的异常体系
2.3异常规范
3.异常的优缺点
3.1优点
3.2缺点
一.异常
1.1C++异常概念
1.2异常的使用
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 a, b;
cin >> a >> b;
cout << Division(a,b) << endl;
}
int main()
{
try
{
Func();
}
catch (const char* errmsg)
{
cout << errmsg << endl;
}
catch (...)
{
cout << "unkown exception" << endl;
}
return 0;
}
当发生除零错误时会被抛出,被catch捕获,catch(...)可以捕获任意类型的异常,但会优先去匹配最适合的。
1.3异常和栈帧,重新抛出
如图
也就是要去匹配最适合的catch语句。
有可能单个的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 a, b;
cin >> a >> b;
cout << Division(a,b) << endl;
}
void show()
{
int* arr = new int[10];
Func();
delete[] arr;
}
int main()
{
try
{
show();
}
catch (const char* errmsg)
{
cout << errmsg << endl;
}
catch (...)
{
cout << "unkown exception" << endl;
}
return 0;
}
当发生除零错误时,通过throw直接跳到catch语句后,往后执行,而show()函数内new 出来的空间未释放。
解决办法:
void show()
{
int* arr = new int[10];
try {
Func();//若Func函数出现异常,将前面的arr释放
}
catch (...)
{
delete[]arr;
throw; //重新抛出
}
delete[] arr;
}
二.异常体系
2.1自定义异常体系
可以定义一套继承的规范异常体系,抛出继承的派生类,捕获一个基类即可。
例如:
定义一个父类,两个子类。发生异常,抛出子类,在子类中填充错误信息,用父类接受,通过多态实现,打印错误信息。
class A
{
public:
A(const string str, int id)
:str_(str)
,id_(id)
{}
virtual string what() const
{
return str_;
}
string str_;
int id_;
};
class Aa : public A
{
public:
Aa(string str,int id,string stra)
:stra_(stra)
,A(str,id)
{}
virtual string what() const
{
string Str("Aa");
Str += stra_;
return Str;
}
private:
string stra_;
};
class Ab :public A
{
public:
Ab(string str, int id, string strb)
:strb_(strb)
,A(str,id)
{}
virtual string what() const
{
string Str("Ab");
Str += strb_;
return Str;
}
private:
string strb_;
};
void AAA()
{
//若发生错误
throw Aa("AAA", 8, "AAAA");
}
void BBB()
{
//若发生错误
throw Ab("BBB", 9, "BBBB");
}
void show()
{
AAA();
BBB();
}
int main()
{
try {
show();
}
catch (A& a)
{
cout << a.what() << endl;
}
return 0;
}
结果:
2.2C++标准库的异常体系
C++ 提供了一系列标准的异常,我们可以在程序中使用这些标准的异常。它们是以父子类层次结构组织起来的。
① 在上述继承体系中,每个类都有提供了构造函数、复制构造函数、和赋值操作符重载。
② logic_error类及其子类、runtime_error类及其子类,它们的构造函数是接受一个string类型的形式参数,用于异常信息的描述
③ 所有的异常类都有一个what()方法,返回const char* 类型(C风格字符串)的值,描述异常信息。
对异常的一写说明:
简单看个例子:
2.3异常规范
1.在函数后加上throw(类型A,类型B)
可以列出这个函数能抛出的所有异常类型
void test() throw(string,vector<int>);
2,如果只跟一个类型,代表该函数只会抛出一种类型的异常
void* operator new(size_t size) throw (std::bad_alloc);
3.如果跟的是throw()
代表这个函数不会抛出异常
void* test(size_t sz, void* p) throw();
4.noexcept
来标识不会抛出异常
void* test(size_t sz, void* p) noexcept;
例如:
3.异常的优缺点
3.1优点
1.将异常对象定义好后,相比错误码的方式可以清晰准确的展示出错误的各种信息,更加直观。
2.传统返回错误码的方式去返回错误码时,需要层层返回。
3.很多的第三方库都包含异常,比如boost、gtest等等常用的库,那么我们使用它们时也需要使用异常。
4. 部分函数使用异常更好处理,比如构造函数没有返回值,不方便使用错误码方式处理。比如 T& operator这样的函数,如果pos越界了只能使用异常或者终止程序处理,没办法通过返回 值表示错误。
3.2缺点
1.异常的执行流跳动比较大,有时可能很难追踪错误。
2.C++没有垃圾回收机制,异常非常容易导致内存泄漏、死锁等异常安全问题。(使用RAII来处理资源的管理问题)。
3.异常需要规范去使用,依赖用户的规范,习惯。