Effective C++ 之 析构函数

本文探讨了析构函数中处理异常的重要性,强调了避免异常逃离析构函数的策略,包括使用try...catch...块进行异常捕获与处理。同时,文章指出在构造和析构函数内调用虚函数可能导致的多态性问题,并详细解释了如何通过复制成员变量来解决自我赋值问题,以及在实现时考虑异常安全性的必要性。

    今天比较郁闷,但仍然还是要坚持的,前几十年的经验告诉我,不坚持,不成功!不忍耐,不成功!

关于析构函数只讲两点:

    POINT 11. 不要让异常从析构函数中跑掉,因为这样,就会导致你的程序脱离了自己的控制。

方法就是,在析构函数里加try...catch...,要么自己把自己的程序abort掉,或者把这个异常自己吞掉,不管能不能消化。至少自己还掌握着自己的生命。

    因为不是所有的程序都会有机会产生异常,这里也只是说那些有很大风险产生异常的函数,还是需要以下这么做的。举例如下:

     class A

     {

          A(){}

          ~A

          {

               try

               {

                    exception();

               }

               catch(...)

               {

                    std::abort;    //abort yourself

                    //or log it and continue to do

                    ...

                }

           }

 

     private:

           exception(){...};

     }

         

POINT12, 不要在构造和析构函数里调用virutal函数

     原因是,在构造和析构函数里调用virtual函数,是不会起到多态的效果的,比如在base class的构造函数里调用了一个virtual的函数fun(),实际上call的函数base class的fun()。为什么?因为创建derived class的对象时,它的构造顺序是先构造父类的,然后才是子类的,在构造父类对象时,子类那个成员变量和那些函数还都没有被初始化呢,编译器能找到的只有父类的fun()。

     同理啊,在析构的时候也是一样的,因为首先析构了子类的对象,等call到父类析构的时候,能找到的fun()也只是父类的而已。

过程就是这样,所以不要试图在构造析构里使用多态的特性!

 

POINT13,关于重载=,请返回reference &,请注意自我赋值

    我前面也讲过了,关于copy assignment,但那时只是将它声明,没有实现,现在我们来看如何实现和正确的实现。

对于这种情况 int x = y = z = 5; 我们可以看出,=的返回值是需要做左值的,另外由于pass by value与pass by reference,在OOC++中当然选择pass by reference,所以近乎我们可以得到一个标准的copy assignment声明式:

    template <typename T>

    T& operator = (const T& t) { ...; return *this; }

    下面对于实现的部分进一步分析,上面看到,我返回的是return *this;但很有可能客户会做下面的操作:

    t = t; //很白痴,那是一位这个看起来很明显而已

    如果是这样的

    T *pt1 = &t;

    T *pt2 = &t;

    *pt1 = *pt2;   //这样就不太明显了吧

    如果是下面这样

    class baseClass{...}

    class derivedClass {...}

    void doSomething( baseClass& bc, derivedClass* pdc)

    {    bc = *pdc; }    //而这两个参数指向的是同一个对象,你还能那么明显的看出来吗?

所以,有必要避免以下这个问题,方法很简单,就是做个indentity test

    class Bitmap { ... };

    class T

    {

     public:

         T & operator = (const T& t)

        {

             if(*this == t)  return *this;   //identity test

            

             delete pBitmap;

             pBitmap= new Bitmap(*t.pBitmap);

             return *this;

         }

     private:

         Bitmap* pBitmap;        

    }

    ok,到现在为止解决了自身赋值的问题。但是,仍然还有一个异常安全性(exception safety)的问题。比如就是Bitmap出现了异常,可能是内存不足导致异常,所以,当返回*this后,pBitmap仍然还是无效的,所以我们还是要继续解决这个问题。

    这种方法号称连自我赋值都可以避免了,可谓一箭双雕,如下:

        T & operator = (const T& t)

        {

             Bitmap* pOri = pBitmap;                  //backup the original pointer

             pBitmap= new Bitmap(*t.pBitmap);   //create the new one

             delete pOri ;     //delete the old one

            

             return *this;

         }

 

不过我现在还是不明白这个就能防止exception了,只是先备份了一个指针,new Bitmap时出现异常,然后删除旧的bitmap对象,pBitmap不是还指在一个已经被删除的对象上吗??

 

虽然明天是端午节,有一个星期的假期,但我现在心情不好,没心情搞清这个问题了,目前只是知道exception safe很重要,以前基本没有注意过,也没有使用过。下次解释了... ...

 

一直在一个地方无谓的努力真是一种悲哀,你的视野越来越小,你的经历越来越少,你的年龄越来越大。现在的我就像一个平庸的小程序,每天都在这里循环着,一直没有退出过这个loop,都快6年了,我现在很需要一个break或者一个不会被catch的exception。这样你的生活就会大不同了,虽然还是会掉到另外一个循环中,但是条件和运行环境是不会一样的,努力加油,还有最后一个月的时间了!!!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值