C++标准提供的标准异常类
这些类以exception为基类,标准程序库抛出的类型对象,都是其派生类的对象。该类包含一个成员函数
virtual const char* what() const throw();
表明返回值为一个字符串,且不抛出任何异常。该函数可在派生类中重定义。
习惯上,我们可以使用标准库中的异常类,如果不满足程序要求,可以自定义异常类。自定义异常类建议派生自Exception类或其派生类。
各种派生标准异常类
异常类 | 头文件及含义 |
---|---|
bad_alloc | < exception> 用new动态分配空间失败 |
bad_cast | < new> 执行dynamic_cast失败,即基类向派生类的转换,指针为空 |
bad_typeid | < typeinfo> 对空指针p执行typeid(*p),判断运行时多态对象的类型失败 |
bad_exception | < typeinfo>当某一函数fun()在执行过程中抛出了异常声明不允许的异常而调用unexpected()函数时,若unexpected()函数再次抛出fun()函数异常声明所不允许的异常,且fun()异常明明列表中有bad_exception ,则会有一个bad_exception 异常在fun()函数调用点被抛出。 |
ios_base::failure | < ios>C++的输入输出流执行过程中发生的错误。 |
underflow_error | < stdexcept>算术运算时向下溢出 |
overflow_error | < stdexcept>算术运算时向上溢出 |
rang_error | < stdexcept>内部计算时发生作用域的错误 |
out_of_range | < stdexcept>表示参数值不在允许的范围内 |
length_error | < stdexcept>尝试创建一个长度超过最大允许值的对象 |
invalid_argument | < stdexcept>表示向函数传的参数无效 |
domain_error | < stdexcept>执行一段程序的先决条件不足 |
后七个类
- runtime_error
underflow_error、overflow_error、rang_error这三个类其实是runtime_error的派生类。而runtime_error是exception类的派生类。runtime_error代表运行时出错,即运行时动态判断的错误。常用的就比如判断溢出。
- logic_error
out_of_range、length_error、invalid_argument、domain_error这四个类是logic_error的派生类,logic_error同样是exception类的派生类。logic_error代表逻辑错误,及在运行前,根据程序运行逻辑能够判断出来的错误。如果小心编写程序,并使用合法输入的话,logic_error可以避免。而非法输入可能会引起函数崩溃,引入异常处理可以提高程序运行的健壮性,避免非法输入引起的程序崩溃。
传递具体的错误信息
这七个类,或者说runtime_error和logic_error都有一个接受const string&型参数的构造函数。在抛出异常构造对象时,可以将具体的错误信息传递给该函数。通过调用what()函数得到构造时提供的错误信息。
#include<iostream>
#include<stdexcept>
using namespace std;
void fun(double a) throw(out_of_range)
{
if (a > 10)
throw out_of_range("Parameter not in range");
}
int main()
{
try
{
fun(20);
}
catch (exception &e)
{
cout << "Error:" << e.what() << endl;
}
return 0;
}
输出为
Error:Parameter not in range
C++标准库的稳定性
C++保证,C++标准程序库在面对异常时,保证不发生资源泄漏,也不破坏容器的不变特性。
- 对于以结点实现的容器,如list、set、map及multiset、multimap,如果结点构造失败,容器应当保持不变。并保证删除结点操作不会失败。
- 对于以数组实现的容器,如vector、deque,由于有时需要调用复制构造函数和复制赋值运算符,当这些操作失败而抛出异常时,容器的不变性不能保证,除此以外,同以结点实现的容器一样。
自定义unexpected()
通过set_unexpected()函数,参数为自定义的unexpected函数名。
#include<iostream>
#include<stdexcept>
#include<exception>
using namespace std;
class A
{
public:
A();
~A();
private:
};
A::A()
{
}
A::~A()
{
}
struct MyException
{
const char* message;
MyException(const char* arg) : message(arg) { }
};
void MyUnexpected()
{
cout << "Enter MyUnexpected" << endl;
throw MyException("Exception thrown from MyUnexpected");
}
void fun() throw(A)
{
cout << "enter fun()" << endl;
throw 5;
}
int main()
{
set_unexpected(MyUnexpected);
try
{
fun();
}
catch (MyException &e)
{
cout <<e.message << endl;
}
catch (int &e)
{
cout << e << endl;
}
return 0;
}
不过结果为
enter fun()
5
环境是VS2017,表明这个异常声明接口,完全没用,真的就是为了增加可读性。