• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            牽著老婆滿街逛

            嚴以律己,寬以待人. 三思而后行.
            GMail/GTalk: yanglinbo#google.com;
            MSN/Email: tx7do#yahoo.com.cn;
            QQ: 3 0 3 3 9 6 9 2 0 .

            UNIX下C++實現動態載入對象

              VC里面實現動態對象載入已經不是什么新鮮事情了,很多的plug-in技術就是例子。Unix下,通過動態載入so獲得一個對象也不是什么難事,不過對這個對象的管理就是一件比較麻煩的事情了。一般的需求如下:
              有class TMyObj,準確說TMyObj應該是一個接口,根據不同具體情況會有不同的實現,例如 TMyObj1、TMyObj2等等……而這些TMyObj1和TMyObj2分別保存在不同的so當中,需要根據不同的時候load不同的so,建立相應的對象。由于這些對象都擁有TMyObj的接口,所以對于外部來說對這些類的使用就像對TMyObj的使用一樣。
              看起來好像比較簡單,只要在so里面引出一個函數: 

            TMyObj * onCreateObject(void);


              而函數在so中的具體實現就是建立不同的子類,例如在obj1.so中:

              TMyObj * onCreateObject(void)
               
            return new TMyObj1; }


              使用的時候只需要動態load入obj1.so,并且找到onCreateObject函數的入口,就可以建立一個具有TMyObj接口的TMyObj1了。
              至于釋放對象,一般有兩種方法:
            方法一:
              so中包含另外一個函數:

              void onDestroyObj(void * p)
              
            {
                TMyObj1 
            * tp = (TMyObj1 *)p;
                delete tp;
              }


              從so中導出該函數,并在刪除對象的時候調用。
            方法二:
              TMyObj的析構函數聲明為虛函數,那么從so導出的onCreateObject()建立的對象,直接執行delete刪除就行了,由于析構函數是虛函數,編譯器會正確的調用TMyObj1的析構函數。
              當然,方法二是比較簡單而優雅的方法,既然對于C++來說接口就相當于純虛函數,多增加一個析構的虛函數又何妨呢。但是無論使用哪種方法,都要注意一個問題,就是載入的obj1.so的生命周期要比最后一個TMyObj1的生存周期長。即只要內存中還存在TMyObj1對象,obj1.so就要一直在內存中,不能卸載。要保證這個同步,是比較麻煩的事情。下面就說說我的解決方法:
              
              首先,要選擇一個通用的載入so的lib,這個可以參考一下common c++的DSO(在file.h)里面。(不想使用common c++?我也只是說“參考”而已)。這個支持DLL和so,通過成員函數void *operator[](const char *);獲得指定的symbol的入口。
              其次,就要選擇一個通用的SmartPtr。這個當然Loki是首選,Loki的SmartPtr的靈活性比boost的smart_ptr強多了,而且Loki也小巧的多。
              然后就要實現一個簡單的so的manager,其實應該說是一個動態object的factory:

            class TObjFactory : protected DSO
              
            {
              
            public:
                TObjFactory(
            void);
                
                
            void load(const std::string & strPath);
                
            void * createObj(voidconst throw (TSOException);
              
            protected:
                typedef 
            void * (*funcCreate)(void ** p);
                funcCreate  m_pCreator;
              }
            ;


              可以想象這個類干些什么:load就是載入相應的so,然后獲得so中onCreateObject函數的入口,并賦給成員m_pCreator。而createObj就是調用m_pCreator建立對象。不過有所不同的是 m_pCreator所指向的函數形式是void * funcCreate(void ** p),而多出來void **p用處就是可以讓so中的構造函數中產生的exception能夠傳遞出來。這個不能說不是so的麻煩之處,so中函數的exception不能被外部捕獲,所以只好這樣子做了。
              現在,關鍵的地方來了,就是要保證這個TObjFactory的生存周期了。選擇Loki的SmartPtr就能派上用場了。
              Loki的SmartPtr可以自己選定適用的StoragePolicy,這正是我們需要的,參考DefaultSPStorage,可以做我們的TMySOStoragePolicy:

            template<class T>
               
            class TMySOStoragePolicy
               
            {
                ..
               
            protected:
                
            void Destroy()
                    

                     delete pointee_;
                     m_pFactory 
            = SmartPtr<TObjFactory>();
                    }
               
               
            private:
                SmartPtr
            <TObjFactory> m_pFactory;
                StoredType       pointee_;
               }
            ;

              顯而易見,這樣做的目的就是要保證釋放指針的時候就減少TObjFactory的引用計數。
              好了,現在就是主角了:
              

            template<class T>
              
            class TDObj : public SmartPtr<T,RefCounted,DisallowConversion,AssertCheck,TMySOStoragePolicy>
              
            {
              
            public:
                TDObj(
            void);
                TDObj(
            const TDObj & obj);
                ..
                
              
            protected:
                friend 
            class TDObjManager;
                TDObj(T 
            * p, SmartPtr<TObjFactory> pManager);
              }
            ;
              
              
            class TDObjManager
              
            {
              
            public:
                
                template
            <class T>
                 
            static TDObj<T>  createObj(const std::string & strKeyName)
                 
            {
                   SmartPtr
            <TObjFactory> pFactory = getFactoryByName(strKeyName);
                   
            //這里面可以做很多事情了,例如訪問內存,查找相應的Factory;或者讀取配置文件、讀入新的so并建立新的Factory。
                   
            //或者根據一些淘汰算法,先淘汰內存的Factory,然后重新載入新的Factory等等。
                   std::auto_ptr<T> _au( static_cast<*>(pFactory->createObj()) );
                   
            return TDObj<T>( _au.release(), pFactory);
                 }

              }
            ;

              
              以后用起來就簡單多了:
              

            class TMyObj
              
            {
              
            public:
               
            virtual ~TMyObj(void);
               
            virtual int func(void= 0;
              }
            ;
              
              TDObj
            <TMyObj> obj1 = TDObjManager::createObj<TMyObj>"obj1.so") );
              TDObj
            <TMyObj> obj2 = TDObjManager::createObj<TMyObj>"obj2.so") );
              
              cout 
            << obj1->func() << endl;
              cout 
            << obj2->func() << endl;


              說了這么久,都是主程序的調用,而so中應該如何呢?其實也很簡單:
              

            class TMyObj1 : public TMyObj
              
            {
              
            public:
                TMyObj1(
            void);
                
            ~TMyObj1(void);

                
            static void onStaticInit(void);
                
            static void onStaticDestroy(void);
                
            static const char * getVersion(void);
                
            static const char * getObjectName(void);
                
                
            virtual int  func(void);
              }
            ;
              
              DECLARE_SO_INTERFACE(TMyObj1);

              
              DECLARE_SO_INTERFACE其實是一個為了方便編寫程序而定義的宏:

            #define DECLARE_SO_INTERFACE(x) extern "C" { \
                
            void onInstallDLL(void);   \
                
            void onUninstallDLL(void);   \
                
            const char * onGetVersion(void); \
                
            const char * onObjectName(void); \
                
            void * onCreateObject(void ** ppException);  \
               }; \
               
            void onInstallDLL(void{ x::onStaticInit(); }    \
               
            void onUninstallDLL(void{ x::onStaticDestroy(); }  \
               
            const char * onGetVersion(voidreturn x::getVersion(); }  \
               
            const char * onObjectName(voidreturn x::getObjectName(); } \
               
            void * onCreateObject(void ** pException) { \
                
            try { \
                 
            *pException = NULL; x * p = new x(); return (void *)p; \
                }
            catch(std::exception & e) { \
                 
            *pException = new std::exception(e); \
                 
            return NULL;  \
                }
             \
               }

               
              可以看到除了導出onCreateObject函數以外,還導出了:
              TMyObj1::onStaticInit用于載入so的時候執行初始化操作;
              TMyObj1::onStaticDestroy用于卸載so的時候執行清理操作;
              TMyObj1::getVersion 獲得對象的版本信息
              TMyObj1::onObjectName 獲得對象名信息等
              可以擴展前面的TObjFactory,實現這些功能。

              同理,我們可以做obj2.so:

            class TMyObj2 : public TMyObj
              
            {
              
            public:
               TMyObj2(
            void);
               
            ~TMyObj2(void);
              
               
            static void onStaticInit(void);
               
            static void onStaticDestroy(void);
               
            static const char * getVersion(void);
               
            static const char * getObjectName(void);
              
               
            virtual int  func(void);
              }
            ;
              
              DECLARE_SO_INTERFACE(TMyObj2);

              
              
              另外,一個值得討論的問題是:C++由于沒有反射機制,所以無法實現設值注入和構造注入,只能實現接口注入。不過一般來說也已經足夠使用了。

            posted on 2006-09-05 13:07 楊粼波 閱讀(836) 評論(0)  編輯 收藏 引用 所屬分類: 文章收藏C++

            久久精品国产亚洲AV久| 久久精品国产半推半就| 尹人香蕉久久99天天拍| 久久久久波多野结衣高潮| 日韩人妻无码精品久久免费一| 久久综合精品国产二区无码| 久久99精品久久久久久动态图| 亚洲天堂久久精品| 色综合久久88色综合天天 | 色8久久人人97超碰香蕉987| 久久最新精品国产| 久久亚洲AV成人无码软件| 99久久99久久精品免费看蜜桃| 色综合久久久久网| 亚洲人成网站999久久久综合 | 人人狠狠综合久久亚洲高清| 国产美女亚洲精品久久久综合| 久久99国产乱子伦精品免费| 久久久久久久久久久免费精品| 亚洲国产精品无码久久一线| 久久99国产亚洲高清观看首页| 亚洲国产日韩欧美综合久久| 国产美女久久精品香蕉69| 亚洲国产综合久久天堂| 国产69精品久久久久777| 久久人与动人物a级毛片| 精品久久久久久99人妻| 精品久久久久久无码专区| 一日本道伊人久久综合影| 国产精品免费久久久久影院| 一本一本久久aa综合精品| 2020最新久久久视精品爱| 午夜精品久久久久久久久| 日韩va亚洲va欧美va久久| 久久精品国产一区二区电影| 精品午夜久久福利大片| 久久久久无码精品国产不卡| 久久99精品久久久大学生| 久久亚洲国产精品成人AV秋霞| 中文成人久久久久影院免费观看| 久久人妻少妇嫩草AV无码蜜桃|