09--异常
1、C语言传统的错误处理方式:
包括终止程序和返回错误码两种方式。
直接使用assert终止程序过于粗暴:用户无意的小错误也会造成程序结束运行。
return返回错误码,再通过错误码查找错误类型:过程繁琐,对用户专业要求高。
2、C++异常概念:
异常是一种错误处理机制,通过throw
抛出异常,并通过try
和catch
进行捕获和处理。
try
{
// 正常业务代码(会抛出异常)
}catch( Exception e1 )
{
// 异常情况1
}catch( Exception e2 )
{
// 异常情况2
}catch( ... )
{
// 捕捉剩余异常
}
3、异常的使用:
-
- 异常的抛出和捕获遵循类型匹配原则,声明的异常类型不会隐式类型(int不会匹配double、const char* 不会匹配 string)。
- 异常对象抛出后会生成拷贝,原始对象在捕获后销毁。
catch(...)
可以捕获任意类型的异常。
#include<iostream>
using namespace std;
double Division(double a, double b)
{
if (b == 0)
{
throw "[error] b == 0";
}
return a / b;
}
int main()
{
try
{
cout << (Division(1, 0));
}
catch (const char* errmsg)
{
cout << errmsg << endl;
}
return 0;
}
-
- 异常的重新抛出允许异常传递给更外层的函数处理。
- 异常安全强调在构造函数和析构函数中避免抛出异常,以防止资源泄漏。
- 异常规范说明了函数可能抛出的异常类型。
double Division(double a, double b) throw(const char*)
{ // 异常规范 表示这个函数只会抛出的异常类型
if (b == 0)
{
throw "[error] b == 0";
}
return a / b;
}
double Add(double a, double b) throw()
{ // 表明不会抛出异常 c++11后可以使用noexcept
return a + b;
}
4、自定义继承的异常体系:
异常的捕捉同样支持“多态”,捕捉基类对象的声明会同时捕捉派生类对象。
公司或项目一般都会利用此机制自定义一套异常体系,以规范异常的使用和管理。
#include<iostream>
using namespace std;
class error
{
public:
error(const string& s)
:_errmsg(s)
{}
protected:
string _errmsg;
};
class numerror :public error
{
public:
numerror(const string& msg, int x)
:error(msg),
_a(x)
{}
friend ostream& operator<<(ostream& out, const numerror& x);
private:
int _a;
};
ostream& operator<<(ostream& out, const numerror& x)
{
out << x._errmsg << ' ' << x._a << endl;
return out;
}
double Division(double a, double b) throw(error) // 异常规范 表示这个函数只会抛出的异常类型
{
if (b == 0)
{
throw numerror("[error] b == 0", b);
}
return a / b;
}
double Add(double a, double b) throw() // 表明不会抛出异常 c++11后可以使用noexcept
{
return a + b;
}
int main()
{
try
{
cout << (Division(1, 0)) << endl;
}
catch (numerror errmsg)
{
cout << errmsg << endl;
}
return 0;
}
解释:
-
error
类是一个基类,用于存储错误信息。numerror
类继承自error
类,增加了一个整数成员_a
来存储与数字相关的错误信息。Division
函数声明时使用了throw(error)
来指定函数可能抛出的异常类型。这意味着Division
函数只会抛出error
类或其派生类的实例。
在代码的抛出规范声明、捕捉类型声明都只需要写基类对象类型,就可以智能多态地完成捕获。
5、C++标准库的异常体系:
C++提供了一系列的标准异常类,以层次结构组织。
#include<iostream>
#include<vector>
using namespace std;
int main()
{
try {
vector<int> v(10, 5);
v.reserve(10);
// 越界抛异常:invalid vector subscript 无效的向量下标
v.at(10) = 100;
}
catch (const exception& e) // 捕获基类对象即可
{
cout << e.what() << endl;
}
catch (...)
{
cout << "Unkown Exception" << endl;
}
return 0;
}
exception是c++提供的异常类,可以将exception作为基类构建自己的异常体系。
6、异常的优缺点:
-
- 优点包括清晰的错误信息展示、简化深层函数错误处理、第三方库支持、适合特定函数的错误处理。
- 缺点包括可能导致程序执行流程混乱、性能开销、资源管理问题、标准库异常体系设计不佳、使用不规范可能导致的问题。