首 页 | 新 闻 | 技术中心 | 第二书店 | 《程序员》 | 《开发高手》 | 社 区 | 黄 页 | 人 才
移 动专 题SUNIBM微 软微 创精 华Donews人 邮
我的技术中心 
我的分类 我的文档
全部文章 发表文章
专栏管理 使用说明



 RSS 订阅 
最新文档列表
Windows/.NET
.NET  (rss)    
Visual C++  (rss)    
Delphi  (rss)    
Visual Basic  (rss)    
ASP  (rss)    
JavaScript  (rss)    
Java/Linux
Java  (rss)    
Perl  (rss)    
综合
其他开发语言  (rss)    
文件格式  (rss)    
企业开发
游戏开发  (rss)    
网站制作技术  (rss)    
数据库
数据库开发  (rss)    
软件工程
其他  (rss)    

积极原创作者 
tellmenow (22)
cutemouse (22)
softj (78)
iiprogram (69)
qdzx2008 (50)
goodboy1881 (14)
wangchinaking (58)
fancyhf (1)
harrymeng (41)
yjz0065 (113)
CSDN - 文档中心 - Visual C++ 阅读:7819   评论: 6    参与评论
标题   C++深度探索系列:智能指针(Smart Pointer) [二]     选择自 RedStar81 的 Blog
关键字   智能指针(Smart Pointer)、C++、COM
出处  

                                           深度探索智能指针(Smart Pointer)

主题索引:

一、剖析C++标准库智能指针(std::auto_ptr)
   
    1.Do you Smart Pointer?
    2.std::auto_ptr的设计原理
    3.std::auto_ptr高级使用指南
    4.你是否觉得std::auto_ptr还不够完美?

二、C++条件,寻找构造更强大的智能指针(Smart Pointer)的
    策略
   
    1.支持引用记数的多种设计策略
    2.支持处理多种资源
    3.支持Subclassing
    4.支持多线程条件下,线程安全的多种设计策略
    5.其它多种特殊要求下,再构造

三、Generic Programming基础技术和Smart Pointer
    1.回首处理资源中的Traits技术
    2.回首多线程支持的设计


四、COM实现中,Smart Pointer设计原理


五、著名C++库(标准和非标准)中的Smart Pointer现状

---------------------------------------------------------------------

二、C++条件,寻找构造更强大的智能指针(SmartPointer)的策略  
    
              
    
    1.支持引用记数的多种设计策略
     
      你听说过COM和它著名的IUnknown接口吧?
      IUnknown是干什么的?我要告诉你,IUnknown接口三个函数签名中,
      两个是用来管理对象(CoClass Object,组件类对象)的记数来控制
      它的生命周期的.
 
      在实践中,我们的对象并不是只用一次,只允许一个引用的.

      那么,谁来管理它的生命周期呢?
     
      我们的策略是:引用记数. 当对象的引用记数为零时,就销毁对象.
      在没有托管环境的情况下,事实上,销毁对象的往往还是auto_ptr.
      而COM中,销毁对象的是对象自己.
     
      事实上,它和我们的智能指针不是一个级别上的概念.
      我们的智能指针负责的是对象级的引用.而COM是以接口引用为
      核心的.保证接口操作时,接口引用记数的自动管理.
 
      哦!是的!那么我们怎样给auto_ptr加上对象引用记数的功能?

      策略1:
        
         一个对象对应一个引用记数对象.
         智能指针以记数对象为代理.
         想象,这又归到经典的"添加中间层"解决方案上了.
         
         # 核心一:
          
         我们添加一个 "引用记数class".
         它的职责有二:
            a.维护对象的引用记数.
            b.维护对象的指针.
        
         结构示意如下:
         template<class T>
         class ObjRefCounted{
         private:
             T* m_OBJ_Delegate_Ptr;
             unsigned int m_UIcounted;
         public:
      explicit ObjRefCounted(T* m_Paramin = 0):
             m_UIcounted(1), m_OBJ_Delegate_Ptr(m_Paramin){};   
   
      template<class M> ObjRefCounted(ObjRefCounted<M>& x) {
             m_OBJ_Delegate_Ptr = x.m_OBJ_Delegate_Ptr);          };
        
         ObjRefCounted(const ObjRefCounted& x):m_UIcounted
             (x.m_UIcounted), m_OBJ_Delegate_Ptr(x.m_ObjDelegate_Ptr){};
      ~ObjRefCounted();
 
             void ReleaseRef ();
      void AddRef ();
      T* GetRealPointer () const;
         };
        
         # 核心二
           在智能指针中维护一个引用记数class的指针
           template<class T>
           class SmartPointer{
           public:
                 ObjRefCounted* _m_ObjRefCounted;
           .....
           .....
           };
          
           通过上面的两个策略,我们就可以在智能指针构造时,为之付上一个
           引用记数对象.这个对象负责托管Smart Pointer原本应该维护
           的对象指针.并且负责最终消除对象.

           在Smart Pointer中,我们将会涉及大量的_m_ObjRefCounted的操作.
           下面简叙一过程,详细不诉,自己设计之.
           譬如:当你将一个对象指针赋给Smart Pointer将构建一辅助的
           引用记数托管对象,此时m_UIcounted为1,m_OBJ_Delegate_Ptr被赋
           以对象指针,假如现在我又将Smart Pointer 赋给另一SmartPointer2
           , 那么SmartPointer2调用_m_ObjRefCounted->ReleaseRef();
           减少原来维护的对象的记数,将自己的_m_ObjRefCounted置为
           SmartPointer2依附的记数对象,再调用_m_ObjRefCounted->AddRef();
           OK!就是这样的.


      策略2.
           在每一个智能指针内部维护一个对象指针和一个引用记数值的
           的指针.
 
           这里的重点在于维护一个引用记数值的指针,
           它使得Smart Pointer之间保持一致的记数值成为可能.
          
           结构示意如下:
           template<class T>
           class SmartPointer{
           private:
                  T* m_ObjPtr;
                  unsigned int* RefCounted;
           public:
           explicit SmartPoint(T* PARAMin = 0) : m_ObjPtr(PARAMin),
                          RefCounted(new int(1)) { }
           SmartPoint(const SmartPoint<T>& PARAMin2):
           m_ObjPtr(PARAMin2.m_ObjPtr),
           RefCounted(PARAMin2.RefCounted) { ++*RefCounted; }
           ....
           ...
           };
          
           不过这个方法的扩展性很差.
           因为引用记数功能结合到Smart Pointer中去了.
           一般不会用这种方法.
    
           以上面的两种策略为基础,根据实际情况,可设计出更多的记数方法.
           
                
      2.利用Traits(Partial Specialization)技术,
        支持处理多种资源

         
        在no1中,我们提到不可让auto_ptr管理数组,那是因为
        auto_ptr构析函数中调用的是delete的缘故.
        数组不可,其它的如,文件句柄、线程句柄等当然更不可以了.

        下面我们就这个问题来探讨:

          策略1.
          通过函数指针来支持多种资源的处理.
          我们的智能指针将设计成具有两个参数的模板类.
          第一个参数指示:资源的类型
          第二个参数指示:处理资源的函数类型
          
          结构示意如下:

          typedef void FreeResourceFunction(void* p);
          void DealSingleObject(void* p);  
          void DealArray(void* p);
          void DealFile(void* p);
          //
          //  针对特殊的资源加入函数指针声明
          //
          template<class Type , class DealFunction = DealSingleObject>
          class SmartPointer{                                              
          public:
          ~SmartPointer(){ DealFunction(); }
          ...
          ...
          /* Other codes */
          };

          inline void DealSingle(void* p)
          {  
              if(p)  delete p;
          }

          inline void DealArray(void* p){
       if(p)  delete[] p;                
          }
 
          inline void DealFile(void* p){
             if(p)   p->close();
          }  
          //
          //针对特殊资源加入处理函数
          //     

          oK!但是我们在使用这个策略的时候,一定要注意,
          传递进的指针不能是错误的,这个你必须保证.
          当然对上面的结构示意再改造,使之具有更强的
          辨错能力也是可取的.

      3.支持Subclassing

        关于智能指针中的Subclassing,是什么?
        我们先来看一程式片段:
           
        class BaseClass {};
        class Derived : public BaseClass {};
         
        auto_ptr<Derived> m_Derived;
 auto_ptr<Base> m_Base;
         
 auto_ptr<Derived> pDerived = new Derived;
 m_Base = pDerived;
        //
        //m_Derived = (PDerived&)m_Base;   //#1
        //

        看到上面的#1没有,你认为在auto_ptr中,
        它或者同等语义的行为可以执行?
        不可以.为什么?
        它本质上,相当与这样的操作:
        BaseClass* m_BaseClass;
        m_BaseClass = new DerivedClass(inParam);
        这显然是非法的.
         
        在上面我们曾经,auto_ptr对具有虚拟特性的类,
        也能体现出虚拟性.

        然而那并不能访问继承的数据,实现的不是真正意义
        上的SubClassing.

        那么,我们这样来实现这样的功能.
         
          策略1.
          在上述引用记数部分叙述的SmartPoint中,我们作如下的操作:
         
   template <class U> SmartPointer& operator = (const SmartPointer<U>& that)
          {
   if (m_pRep ! = reinterpret_cast<RefCountRep<T>* > (that.m_pRep))
   {
     ReleaseRef ();
     m_pRep = reinterpret_cast<RefCountRep<T>* > (that.m_pRep);
     AddRef ();
     }
     return *this;
  }
         };

         不错,reinterpret_cast,就是它帮我们解决了问题.

         策略2.
         关于第二种方法,这里不再详细叙说.
         它涉及太多的细节,峰回路转的很难说清.
         大体上,它是利用引用记数对象中维护的对象指针为void*
         而在具体的调用是通过static_cast或reinterpret_cast转化.
         总之,所谓的SubClassing技术离不开转化.

      4.支持多线程条件下,线程安全的多种设计策略
 
        对于标准C++,多线程问题并不很受关注.
        原因在于目前,标准库并不支持多线程.
       
        策略1:
          首先我们想到:对数据进行访问同步.
          那么,我们有两种方案:
          a. 建立一个临界区对象.将对象的执行传递给临界区对象.
             以保证安全.
          b.利用临时对象来完成任务,将临界的责任留给被作用对象.
         
          下面分析第二种的做法:
          programme1:
          class Widget
          {
           ...
           void Lock();  //进入临界区
           void Unlock(); //退出临界区
          };
       
          programme2:
          template <class T>
          class LockingProxy
          {
            public:
            LockingProxy(T* pObj) : pointee_ (pObj)
            { pointee_->Lock(); }
            //    在临时对象构造是就锁定
            //    weight对象(临界区).
            ~LockingProxy() { pointee_->Unlock(); }
            //           
            //   在临时对象销毁时,退出临界区.
            //
            T* operator->() const
            { return pointee_; }
            //
            //  这里重载->运算符.将对临时对象的方法执行
            //  请求转交给weight对象
            //
            private:
            LockingProxy& operator=(const LockingProxy&);
            T* pointee_;
         };

         programme3:
         template <class T>
         class SmartPtr
         {
            ...
            LockingProxy<T> operator->() const
            { return LockingProxy<T>(pointee_); }
            //
            //  核心就在这里:产生临时对象
            //  LockingProxy<T>(pointee_)
            private:  sT* pointee_;
         };

         Programme4.
         SmartPtr<Widget> sp = ...;
         sp->DoSomething();       //##1

         下面,我们模拟一下,执行的过程.
          ##1执行时,构建了临时对象LockingProxy<T>(pointee_)
          此对象在构造期间就锁定Weight对象,并将DoSomethin()
          方法传递给weight对象执行,在方法执行完,临时对象消失,
          构析函数退出临界区.

      4.其它特殊要求下的再构造
       
        a.回首当年,你是否觉的
          auto_ptr<x> m_SMPTR = new x(100);
          居然通不过.不爽!
          No problem !
          auto_ptr(T* m_PARAMin = 0) shrow() : m_Tp(m_PARAMin){}
          解决问题.
 
       b. Consider it:
          void fook(x* m_PARAMin){};
          可是我只有auto_ptr<x> m_SMPTR;
          No problem !
          T* operator T*(auto_ptr<T>& m_PARAMin) throw ()
          { return m_Tp; }
         
          fook(m_SMPTR); // ok !  now
      c.事实上,你可以根据自己的需要.
        重载更多或加入功能成员函数.

--------------------------------------------------------------
                       待续

三、Generic Programming基础技术和Smart Pointer
    1.回首处理资源中的Traits技术
    2.回首多线程支持的设计


四、COM实现中,Smart Pointer设计原理


五、著名C++库(标准和非标准)中的Smart Pointer现状

--------------------------------------------------------------


--------------------------------------------------------------
                          郑重声明:
                 允许复制、修改、传递或其它行为
                 但不准用于任何商业用途.
                      写于  20/3/2003
                      最后修改: 20/3/2003
                         By RedStar81
                      81_RedStar@163.com
-------------------------------------------------------------


相关文章
对该文的评论
iamltq ( 2003-06-03)
TO:RedStar81:可否也发给我学学?E-mail:iamltq@yahoo.com.cn谢谢^_^
battlet ( 2003-03-27)
我也想看看,嘿嘿
wstwj@hotmail.com,
谢谢了。
Kklee ( 2003-03-26)
mark一下
RedStar81 ( 2003-03-26)

  谢谢zhengyun_ustc哦 !

  zhaohangcom
  邮箱,我发给你啦
zhengyun_ustc ( 2003-03-26)
支持RedStar81一下!