【c++编程思想】异常处理
2012-09-12 10:19
211 查看
c语言中常用的异常处理方式:
1.在函数中返回错误信息,耦合度极高
2.使用标准库中的信号处理系统,signal()能够与推断事件发生时出现了什么情况,和函数raise产生一个事件来实现。耦合度也很高,可能和其他信号冲突
3.非局部跳转函数setjmp,可以在程序中保存一个已知的无错误状态,一旦发生错误就可以使用 longjmp 返回到该状态中。
函数setjmp的行为很特别,如果直接调用它,它便会将所有与当前处理器相关的状态信息保存到jmp_buf中去并返回0,和普通函数一样。
但是当使用同一个jmp_buf调用longjmp时,函数返回就好像刚从setjmp中返回一样,这一次返回值是调用longjmp时所用的第二个参数,因此可以通过这个值来判断实际从哪里返回。
但是c++中使用这种方式的问题在于它无法识别对象,自动调用析构函数。而此时程序的行为是不确定的。
c++形式的异常处理
throw将会导致一系列动作的发生:
创建程序所抛出的对象的一个拷贝,然后包含throw表达式的函数返回了这个对象。
返回一个值,离开函数或者作用域。
异常发生之前创造的局部对象被销毁,这种对局部对象的处理被称为“栈反解”。
捕获所有异常
catch(...){
//do sth
//throw
}
用省略号就可以捕获所有异常,最好将他放在异常处理列表的最后,且不允许接受任何参数,因此一般用于清理资源并且重新抛出异常。
虽然在抛出异常时,会调用析构函数,所有资源都会被清理,但是在构造函数中抛出异常缺不会调用析构函数,会造成内存泄露。
技巧:
在构造函数中捕获异常,用于释放资源
在对象的构造函数中分配资源,并且在对象的析构函数中释放资源
可以讲资源分配称为局部对象生命周期的一部分,如果某次分配失败了,在栈反解的时候,其他已经获得所需资源的对象能够恰当的被清理。资源获得式初始化RAII,他可以使对象对资源控制的事件与对象的生命周期相等。
不捕获异常
如果try之后的异常处理器不能捕获所抛出的异常,那么就会被传递给位于更高层次的语境中的异常处理器,这个过程会持续进行
但是如果没有一个异常处理器能够捕获这种异常,特殊的库函数terminate()会被自动调用。默认情况下,他会调用abort使程序执行异常终止而退出。
set_terminate函数,可以设置读者自己的terminate函数,返回被替换的指向terminate函数的指针。如果terminate函数被调用,就意味着问题已经无法解决了。
可选的异常规格说明
告诉函数使用者可能会抛出的异常
void func() throw (int , char);
1.在函数中返回错误信息,耦合度极高
2.使用标准库中的信号处理系统,signal()能够与推断事件发生时出现了什么情况,和函数raise产生一个事件来实现。耦合度也很高,可能和其他信号冲突
3.非局部跳转函数setjmp,可以在程序中保存一个已知的无错误状态,一旦发生错误就可以使用 longjmp 返回到该状态中。
#include<iostream> #include<csetjmp> using namespace std; class rainbow { public:rainbow(){ cout<<"rainbow()"<<endl; } ~rainbow(){ cout<<"~rainbow"<<endl; } }; jmp_buf kansas; void oz() { rainbow rb; for(int i=0;i<3;i++) { cout<<"no place !!"<<endl; } longjmp(kansas, 47); } int main() { if(setjmp(kansas) == 0) { cout<<"tonado...."<<endl; oz(); } else { cout<<"ooooooooooo"<<endl; } }
函数setjmp的行为很特别,如果直接调用它,它便会将所有与当前处理器相关的状态信息保存到jmp_buf中去并返回0,和普通函数一样。
但是当使用同一个jmp_buf调用longjmp时,函数返回就好像刚从setjmp中返回一样,这一次返回值是调用longjmp时所用的第二个参数,因此可以通过这个值来判断实际从哪里返回。
但是c++中使用这种方式的问题在于它无法识别对象,自动调用析构函数。而此时程序的行为是不确定的。
c++形式的异常处理
throw将会导致一系列动作的发生:
创建程序所抛出的对象的一个拷贝,然后包含throw表达式的函数返回了这个对象。
返回一个值,离开函数或者作用域。
异常发生之前创造的局部对象被销毁,这种对局部对象的处理被称为“栈反解”。
#include<iostream> #include<csetjmp> using namespace std; class rainbow { public:rainbow(){ cout<<"rainbow()"<<endl; } ~rainbow(){ cout<<"~rainbow"<<endl; } }; void oz() { rainbow rb; for(int i=0;i<3;i++) { cout<<"no place !!"<<endl; } throw 47; } int main() { try { cout<<"tonado...."<<endl; oz(); } catch(int a) { cout<<"ooooooooooo"<<" "<<a<<endl; } }
捕获所有异常
catch(...){
//do sth
//throw
}
用省略号就可以捕获所有异常,最好将他放在异常处理列表的最后,且不允许接受任何参数,因此一般用于清理资源并且重新抛出异常。
虽然在抛出异常时,会调用析构函数,所有资源都会被清理,但是在构造函数中抛出异常缺不会调用析构函数,会造成内存泄露。
技巧:
在构造函数中捕获异常,用于释放资源
在对象的构造函数中分配资源,并且在对象的析构函数中释放资源
可以讲资源分配称为局部对象生命周期的一部分,如果某次分配失败了,在栈反解的时候,其他已经获得所需资源的对象能够恰当的被清理。资源获得式初始化RAII,他可以使对象对资源控制的事件与对象的生命周期相等。
不捕获异常
如果try之后的异常处理器不能捕获所抛出的异常,那么就会被传递给位于更高层次的语境中的异常处理器,这个过程会持续进行
但是如果没有一个异常处理器能够捕获这种异常,特殊的库函数terminate()会被自动调用。默认情况下,他会调用abort使程序执行异常终止而退出。
set_terminate函数,可以设置读者自己的terminate函数,返回被替换的指向terminate函数的指针。如果terminate函数被调用,就意味着问题已经无法解决了。
可选的异常规格说明
告诉函数使用者可能会抛出的异常
void func() throw (int , char);
相关文章推荐
- C++编程思想(卷二):异常处理
- C++编程思想(卷二):异常处理
- C++笔记——c++编程思想(下)第一章异常处理
- 了解C++编程中指定的异常和未经处理的异常
- C++编程->异常处理的三重境界
- java编程思想 第十二章 通过异常处理错误
- C++编程->异常处理的三重境界
- 异常的转换思想:当出现的异常是调用者处理不了的,就需要将此异常转换为一个调用者可以处理的异常抛出。
- IT第二十天 - 面向对象编程思想、抽象类、异常处理、程序操作日志记录、本周总结 ★★★
- <Java编程思想>第12章:通过异常处理错误
- Java编程思想学习(九) 异常处理
- java编程思想 bruce Eckel chapter12 通过异常处理错误-chapter22 图形化用户界面
- java编程思想阅读笔记(六)异常处理
- Java编程思想笔记——第十二章 通过异常处理错误
- java编程思想(通过异常处理错误,字符串)
- 异常处理的基本思想
- java编程思想笔记12-通过异常处理错误
- C++异常处理基本思想
- C++编程思想——异常
- C++异常处理基本思想