file://异常 } catch (logic_error& ex) { // 处理所有其它的 ... // logic_errors异常 } 综上所述,把一个对象传递给函数或一个对象调用虚拟函数与把一个对象做为异常抛出,这之间有三个主要区别。第一、异常对象在传递时总被进行拷贝;当通过传值方式捕获时,异常对象被拷贝了两次。对象做为参数传递给函数时不需要被拷贝。第二、对象做为异常被抛出与做为参数传递给函数相比,前者类型转换比后者要少(前者只有两种转换形式)。最后一点,catch子句进行异常类型匹配的顺序是它们在源代码中出现的顺序,第一个类型匹配成功的catch将被用来执行。当一个对象调用一个虚拟函数时,被选择的函数位于与对象类型匹配最佳的类里,即使该类不是在源代码的最前头。
灵巧指针 第一次用到灵巧指针是在写ADO代码的时候,用到com_ptr_t灵巧指针;但一直印象不是很深;其实灵巧指针的作用很大,对我们来说垃圾回收,ATL等都会使用到它,在More effective 的条款后面特意增加这个节点,不仅是想介绍它在异常处理方面的作用,还希望对编写别的类型代码的时候可以有所帮助。
smart pointer(灵巧指针)其实并不是一个指针,其实是某种形式的类。 不过它的特长就是模仿C/C++中的指针,所以就叫pointer 了。所以希望大家一定要记住两点:smart pointer是一个类而非指针,但特长是模仿指针。
那怎么做到像指针的呢? C++的模板技术和运算符重载给了很大的发挥空间。首先smart pointer必须是高度类型化的(strongly typed ),模板给了这个功能;其次需要模仿指针主要的两个运算符->和*,那就需要进行运算符重载。
详细的实现: template<CLASS&NBSP;T> class SmartPtr { public: SmartPtr(T* p = 0); SmartPtr(const SmartPtr& p); ~SmartPtr(); SmartPtr& operator =(SmartPtr& p); T& operator*() const {return *the_p;} T* operator->() const {return the_p;} private: T *the_p; } 这只是一个大概的印象,很多东西是可以更改的。比如可以去掉或加上一些const ,这都需要根据具体的应用环境而定。注意重载运算符*和->,正是它们使smart pointer看起来跟普通的指针很相像。而由于smart pointer是一个类,在构造函数、析构函数中都可以通过恰当的编程达到一些不错的效果。
举例: 比如C++标准库里的std::auto_ptr 就是应用很广的一个例子。它的实现在不同版本的STL 中虽有不同,但原理都是一样,大概是下面这个样子: template<CLASS&NBSP;X> class auto_ptr { public: typedef X element_type; explicit auto_ptr(X* p = 0) throw() : the_p(p) {} auto_ptr(auto_ptr& a) throw() : the_p(a.release()) {} auto_ptr& operator =(auto_ptr& rhs) throw() { reset(rhs.release()); return *this; } ~auto_ptr() throw() {delete the_p;} X& operator* () const throw() {return *the_p;} X* operator-> () const throw() {return the_p;} X* get () const throw() {return the_p;} X* release() throw() { X* tmp = the_p; the_p = 0; return tmp; } void reset(X* p = 0) throw() { if (the_p!=p) { delete the_p; the_p = p; } } private: X* the_p; }; 关于auto_ptr 的使用可以找到很多的列子,这里不在举了。它的主要优点是不用 delete ,可以自动回收已经被分配的空间,由此可以避免资源泄露的问题。很多Java 的拥护者经常不分黑白的污蔑C++没有垃圾回收机制,其实不过是贻笑大方而已。抛开在网上许许多多的商业化和非商业化的C++垃圾回收库不提, auto_ptr 就足以有效地解决这一问题。并且即使在产生异常的情况下, auto_ptr 也能正确地回收资源。这对于写出异常安全(exception-safe )的代码具有重要的意义。
在使用smart pointer 的过程中,要注意的问题: 针对不同的smart pointer ,有不同的注意事项。比如auto_ptr ,就不能把它用在标准容器里,因为它只在内存中保留一份实例。把握我前面说的两个原则:smart pointer 是类而不是指针,是模仿指针,那么一切问题都好办。比如,smart pointer 作为一个类,那么以下的做法就可能有问题。 SmartPtr p; if(p==0) if(!p) if(p) 很显然, p 不是一个真正的指针,这么做可能出错。而SmartPtr 的设计也是很重要的因素。 您可以加上一个bool SmartPtr::null() const 来进行判断。如果坚持非要用上面的形式, 那也是可以的。我们就加上operator void* ()试试: template<CLASS&NBSP;T> class SmartPtr { public: ... operator void*() const {return the_p;} ... private: T* the_p; }; 这种方法在basic_ios 中就使用过了。这里也可以更灵活地处理,比如类本身需要operator void*()这样地操作,那么上面这种方法就不灵了。但我们还有重载operator !()等等方法来实现。
总结smart pointer的实质: smart pointer 的实质就是一个外壳,一层包装。正是多了这层包装,我们可以做出许多普通指针无法完成的事,比如前面资源自动回收,或者自动进行引用记数,比如ATL 中CComPtr 和 CComQIPtr 这两个COM 接口指针类。然而也会带来一些副作用,正由于多了这些功能,又会使 smart pointer 丧失一些功能。
WIN结构化异常 对使用WIN32平台的人来说,对WIN的结构化异常应该要有所了解的。WINDOWS的结构化异常是操作系统的一部分,而C++异常只是C++的一部分,当我们用C++编写代码的时候,我们选择C++的标准异常(也可以用MS VC的异常),编译器会自动的把我们的C++标准异常转化成SEH异常。
微软的Visual C++也支持C + +的异常处理,并且在内部实现上利用了已经引入到编译程序和Wi n d o w s操作系统的结构化异常处理的功能。
S E H实际包含两个主要功能:结束处理( termination handling)和异常处理( e x c e p t i o nh a n d l i n g)。
在MS VC的FAQ中有关于SHE的部分介绍,这里摘超其中的一句: “在VC5中,增加了新的/EH编译选项用于控制C++异常处理。C++同步异常处理(/EH)使得编译器能生成更少的代码,/EH也是VC的缺省模型。”
一定要记得在背后的事情:在使用SHE的时候,编译程序和操作系统直接参与了程序代码的执行。 Win32异常事件的理解 我写的另一篇文章:内存处理和DLL技术也涉及到了SHE中的异常处理。
Exception(异常处理) 分成软件和硬件exception 2种。如:一个无效的参数或者被0除都会引起软件exception,而访问一个尚未commit的页会引起硬件exception. 发生异常的时候,执行流程终止,同时控制权转交给操作系统,OS会用上下文(CONTEXT)结构把当前的进程状态保存下来,然后就开始search 一个能处理exception的组件,search order如下: 1、 首先检查是否有一个调试程序与发生exception的进程联系在一起,推算这个调试程序是否有能力处理 2、 如上面不能完成,操作系统就在发生exception event的线程中search exception event handler 3、 search与进程关联在一起的调试程序 4、 系统执行自己的exception event handler code and terminate process
结束处理程序 利用S E H,你可以完全不用考虑代码里是不是有错误,这样就把主要的工作同错误处理分离开来。这样的分离,可以使你集中精力处理眼前的工作,而将可能发生的错误放在后面处理。
|
请发表评论