1,问题:
1,如果在 main 函数中抛出异常会发生什么?
1,不处理,则崩溃;
2,如果异常不处理,最后会传到哪里?
3,下面的代码输出什么?
4,异常的最终处理编程实验:
1 #include <iostream> 2 3 using namespace std; 4 5 class Test 6 { 7 public: 8 Test() 9 { 10 cout << "Test()"; 11 cout << endl; 12 } 13 14 ~Test() 15 { 16 cout << "~Test()"; 17 cout << endl; 18 } 19 }; 20 21 int main() 22 { 23 static Test t; // BCC Test(); 24 // VC 2010 Test(); 25 // G++ Test(); 26 27 throw 1; // BCC Abnormal program termination; 28 // VC 对话框弹出来; 29 // G++ terminate called after throwing an instance of 'int'; 30 31 return 0; 32 }
1,有了线索,main() 函数中抛出的异常也许会被一个最终的函数处理;
5,异常无法被处理的情况:
1,如果异常无法被处理,terminate() 结束函数会被自动调用;
2,默认情况下,terminate() 调用库函数 abort() 终止程序;
1,三款编译器在 terminate() 函数内部实现上面有点儿差异;
2,比如打印字符串提示当前程序出来异常,弹出对话框告诉用户当前应程序要异常终止(实际还没终止);
3,abort() 函数使得程序执行异常而立即退出;
4,C++ 支持替换默认的 terminate() 函数实现;
1,C++ 可以自定义结束函数,自定义最终处理异常的函数来替换预定义的 terminate();
6,terminate() 函数的替换:
1,自定义一个无返回值无参数的函数;
1,不能抛出任何异常;
1,最后处理异常的函数了,所以不能抛出任何异常;
2,必须以某种方式结束当前程序;
1,没有做到这一点儿,程序出现什么样的行为就不得而知了,当然 Windows 和 Linux 系统会将这个程序自动终止;
2,调用 set_terminate() 设置自定义的结束函数;
1,参数类型为 void(*)();
1,函数指针,没有参数、没有返回值;
2,返回值为默认的 terminate() 函数入口地址;
7,自定义结束函数编程实验:
1 #include <iostream> 2 #include <cstdlib> 3 #include <exception> // C++ 标准库中与异常相关的头文件; 4 5 using namespace std; 6 7 void my_terminate() 8 { 9 cout << "void my_terminate()" << endl; 10 exit(1); // 结束当前的程序;可以确保所有的全局对象和静态局部对象全部都正常析构; 11 // abort(); // “已放弃”是这个函数打印出来的,这个函数是异常终止一个程序,并且异常终止的时候不会调用任何对象的析构函数; 12 } 13 14 class Test 15 { 16 public: 17 Test() 18 { 19 cout << "Test()"; 20 cout << endl; 21 } 22 23 ~Test() 24 { 25 cout << "~Test()"; 26 cout << endl; 27 } 28 }; 29 30 int main() 31 { 32 set_terminate(my_terminate); 33 34 static Test t; 35 36 throw 1; 37 38 return 0; 39 }
1,打印结果:
1,exit(1) 的时候:
Test()
void my terminate()
~Test()
2,abort() 的时候:
Test()
void my terminate()
已放弃
2,在 main() 函数中扔出的异常如果没有被处理,会被最终的一个全局结束函数处理掉;
3,C++ 编译器之间存在差异;
8,问题:
1,如果析构函数中抛出异常会发生什么情况?
1,前面说有可能导致资源无法释放,内存泄漏等;
2,这里有两点:
1,析构函数是释放资源的地方,如果抛出异常,有可能导致资源无法正确的释放;
2,在析构函数中抛出异常有可能导致全局的结束函数 terminate() 被重复的调用,这是很可怕的,有可能让我们的系统进入一个不稳定的状态;
2,析构函数抛出异常编程实验:
1 #include <iostream> 2 #include <cstdlib> 3 #include <exception> 4 5 using namespace std; 6 7 void my_terminate() 8 { 9 cout << "void my_terminate()" << endl; 10 // exit(1); 11 abort(); 12 } 13 14 class Test 15 { 16 public: 17 Test() 18 { 19 cout << "Test()"; 20 cout << endl; 21 } 22 23 ~Test() 24 { 25 cout << "~Test()"; 26 cout << endl; 27 28 throw 2; 29 } 30 }; 31 32 int main() 33 { 34 set_terminate(my_terminate); 35 36 static Test t; 37 38 throw 1; 39 40 return 0; 41 }
1,打印结果:
1,Test()
void my terminate() // main() 中 throw 1 抛出异常后第一次执行 my_terminate() 函数的结果;
~Test() // 调用 exit(),执行析构函数;
void my terminate() // 在执行析构函数的时候,再次扔出异常 throw 2,第二次执行 my_terminate() 函数;
2,my_terminate() 函数:
1,作为最后一个被调用的异常处理函数,任务是很重的;
2,要负责进行应用程序级别的资源释放;
3,第一次调用的时候,所有的资源已经被释放完了,第二次调用就类似对堆空间的内存第二次释放,造成应用程序的不稳定,因为这里 Linux 系统非常稳定,会帮我们处理好连续释放资源的问题;
4,如果进行嵌入式开发,操作系统就不见得有这样的能力对每一个系统做这样的监控,产生的行为使未定义的;
5,这也解释了 C++ 默认调用的是 abort() 而不是 exit(1),因为 abort() 直接的强制结束当前的应用程序,不会调用析构函数,就是拍析构函数中扔出异常;
9,小结:
1,如果异常没有被处理,最后 terminate() 结束整个程序;
2,terminate() 是整个程序释放系统资源的最后机会;
3,结束函数可以自定义,但不能继续抛出异常;
4,析构函数中不能抛出异常,可能导致 terminate() 多次调用;