所有标准异常归根结底都是从exception类派生而来,此类定义在头文件exception中
两个主要的派生类为logic_error(报告程序逻辑错误,通过检查代码,能够发现这类错误)
和runtime_error(报告运行错误,只有在程序运行时候,这类错误才能被检查到)
这两个类的定义在头文件stdexcept中,通过exception::what()函数,可以从对象中得到他所保存的消息
一般不要从exception派生类,而是从logic_error或者runtime_error派生自己的类
class x{
4 public:
5 class a{};
6 class b{};
7 class c{};
8 void f(){throw b();}
9 };
10 void f1(){
11 try{
12 x x1;
13 x1.f();
14 }catch(x::a&){
15 cout << "caught a" << endl;
16 }catch(x::b&){
17 cout << "caught b" << endl;
18 }catch(x::c&){
19 cout << "caught c " << endl;
20 }
21 }
在catch语句里面的重新抛出异常使用throw;(仅仅是throw后面一个分号)并且此异常不会被随后的catch捕捉到,而是抛出到更高一层语境中的异常处理器(catch语句)
如果没有任何一个异常处理器能捕捉到某个异常,则系统会自动调用terminate函数(可以使用set_terminate设置此函数)
构造函数没有正常结束时候,不会调用析构函数
class a{
23 public:
24 a(){
25 value ++;
26 cout << "constructor" << value << endl;
27
28 if(3 == value){
29 throw 3;
30 }
31 }
32 ~a(){cout << "destructor" <<value << endl;}
33 private:
34 static int value;
35 };
36 int a::value = 0;
37 void f2(){
38 try{
39 a a1;
40 a a2[5];
41 a a3;
42 }catch(int i){
43 cout << "end" << i <<endl;
44 }
45 }
结果是
constructor1
constructor2
constructor3
destructor3
destructor3
end 3
因为第三个对象(a2[1])构造函数抛出异常,也就是非正常结束了,所以就会导致析构函数不执行
然后捕捉到的值是那个抛出的对象(也就是3),如果前面抛出了10000,end 后面就是10000
(记住:如果一个对象的构造函数在执行过程中抛出异常,那么这个对象的构造函数就不会被调用)这个可能会对象的一部分内存分配成功,一部分失败,或者内存分配成功,但是析构函数没有执行,没有释放内存(delete)
一般呢,防止资源泄露有两个方式
1 在构造函数中捕获异常,用于释放资源
2 在对象的构造函数中分配资源,并且在对象的析构函数中释放资源
class x{
public:
x(int i){}
};
class y{
public:
y(int i):try x(i){}catch(x& x1){
cout << "shit" << endl;
}
};
class a{
5 public:
6 a(int i){}
7 };
8
9 class b{
10 public:
11 b(){}
12 };
13 void f2()throw(a,b);有可能抛出a,b两个类型的异常
14 void f3();可能抛出任何类型的异常
15 void f4()throw();不可能抛出任何类型的异常
如果函数所抛出的异常没有列在异常规格说明集中,一个特殊的函数unexpected()将会被调用,默认的unexpected会调用前面的terminate函数
也可以使用set_unexpected设置此类函数