shared

    技术2022-05-11  122

    Roger( roger2yi@gmail.com) 1. 当作类对象的“共享句柄”来使用 2. 在类内部提供资源管理服务 —— “为类提供资源的共享拷贝语义 (或称为浅拷贝 shadow copy ,并在正确的时间回收资源”   上述的两种方式一种是在类外部使用,一种是在类内部使用,然而这两种方式并不是非此即彼的关系,很多情况下我们都可以选择任意一种,选择其中一种理由通常是遵循“更容易被使用,更难以被误用”的原则。   当作类对象的“共享句柄”来使用   在这种使用方式下,结合Create Method模式使用会取得更好的效果 (关于 Create Method 模式,更多信息请看“模式与重构一书”)。   以下是一个使用场景,我们有一个类,类封装了一个底层资源的句柄和跟句柄相关的所有API调用 (句柄和 API 调用来自操作系统或者其它的 C 函数库)。   句柄在不再被使用的时候需要被释放 (析构函数是最适合做这件事的,不是吗?);   句柄的拷贝可能是一种危险的行为 (通常句柄的实现都是所谓的 Opaque pointer 不透明指针,也是说该指针实际是指向一块 API 操作的数据结构,只是该数据结构是不对外公开的,这也是所谓的 C OO 风格),因为有可能导致悬挂句柄 (其实也是悬挂指针)或者由于释放的责任模糊而导致重复释放。   所以,我们用类封装底层资源句柄,但不为该类提供拷贝行为,而是通过外裹的share_ptr来提供共享拷贝语义。   下面是一个实际例子,来自我自己封装lcms库profile句柄的一个类 lcms 是一个开源用于色彩管理的 C 函数库,也是一个轻量级可用于学习 C-OO 编程的不错选择),cmsHPROFILE是lcms的profile (特性文件)资源句柄。   KProfile.h     #pragma  once #include  " KProfileShPtr.h "  #include  < lcms / lcms.h >   namespace  milk{     /* * The wrapper class of lcms's profile,       group related function together,       and use RAII idiom to manage resource.  */      class  PUREMILK_EXPORT KProfile :  private  boost::noncopyable    {     public :        ~ KProfile( void );        /* * Create method, more information please refer to book           - Refactoring to Patterns.  */          /* * Three basic create methods, from an existing handle,           file and memory.  */         static  KProfileShPtr createFromHandle(cmsHPROFILE);        static  KProfileShPtr createFromFile( const   char * const   char * );        static  KProfileShPtr createFromMemory( void * , UINT32);         /* * Get the internal profile handle of lcms.  */        cmsHPROFILE getHandle()  const  { return  handle_;}         /* * Print out  */        ostream &  print(ostream & const ;         /* * Basic information related function.  */         string                getProductName()  const ;        string                getProductDescription()  const ;        string                getProductInformation()  const ;        string                getManufacturer()  const ;        string                getModel()  const ;        string                getCopyright()  const ;       UINT32               getProfileVersion()  const ;        string                getProfileVersionString()  const ;      private :       KProfile();       KProfile(cmsHPROFILE);       KProfile( const   char * const   char * );       KProfile( void * , UINT32);        cmsHPROFILE       handle_;    };} 1.         KProfile 封装了cmsHPROFILEhandle_句柄,和许多相关的lcms API调用 2.         从boost库的noncopyable获得禁止拷贝的行为(拷贝构造函数和赋值操作符) 3.         KProfile不提供public的构造函数,而是提供一系列的create methods,所有的create methods都返回KProfileShPtrtypedef boost::shared_ptr<KProfile> KProfileShPtr 4.         getHandle函数会返回内部profile句柄(资源封装类应该允许返回内部的句柄或者指针,参看Effective C++第三版)   KProfileShPtr.h   #pragma  once    namespace  milk{     /* * Shared pointer for KProfile.  */      class  KProfile;    typedef boost::shared_ptr < KProfile >        KProfileShPtr;}   1.    另外提供一个KProfileShPtr.h而不把typedef置于KProfile.h内的原因是为了提供KProfileShPtr的前置声明 (类似 C++ 标准库 iosfwd 的做法),就是说当其它类的接口需要使用到KProfileShPtr的时候,它不必在头文件中包括KProfile.h,而只需要包括KProfileShPtr.h即可。(当然在所有的地方都写boost::shared_ptr<KProfile>可以免除这种麻烦,看个人喜好)   KProfile.cpp   #include  " KProfile.h " #include  " KCMSException.h "   namespace  milk{    KProfile::KProfile()       : handle_( 0 )    {    }     KProfile::KProfile(cmsHPROFILE handle)       : handle_(handle)    {    }     KProfile:: ~ KProfile( void )    {        if  ( this -> handle_)           cmsCloseProfile( this -> handle_);    }     KProfileShPtr    KProfile::createFromHandle(cmsHPROFILE handle)    {       KProfile *  profile  =   new  KProfile(handle);        return  KProfileShPtr(profile);    }}   1. 在析构函数中会释放profile句柄 2. 由于KProfile没有提供拷贝行为,所以析构函数不会担心会多次释放同一句柄,当然如果释放发生在类外部,这不是类KProfile可以控制的        

    最新回复(0)