• <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>

            alex

            alex

              C++博客 :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
              7 隨筆 :: 6 文章 :: 7 評(píng)論 :: 0 Trackbacks

            今天來(lái)講講怎么編寫(xiě)異常安全的代碼。
            程序運(yùn)行過(guò)程中,往往需要對(duì)一些流程加入異常處理,來(lái)提高程序的robust.比如
            通過(guò)try catch來(lái)捕捉異常
            try
            {
            ??? pMemory = new char[MAX_BUF_SIZE];
            }
            catch(std::bad_alloc& e)
            {
            ??? //error handling,er:do something resource free
            }
            但在程序代碼段中出現(xiàn)大量的try catch,不僅從美觀,效率和程序輸寫(xiě)上都是不怎么好。
            而另外一種對(duì)于異常的處理方法是依賴于c++的ctor/dctor的匹配來(lái)做的,就是所謂的
            RAII,這個(gè)很容易讓人聯(lián)想到std::auto_ptr
            std::auto_ptr<int> tmp(new int);
            通過(guò)new分配的對(duì)象會(huì)在tmp生命結(jié)束后,釋放相關(guān)的資源,通過(guò)這種方式,就能保證在程序異常,或退出時(shí),已分配的對(duì)象能正確自動(dòng)的釋放擁有的資源,而在對(duì)象聲明周期內(nèi),可以保證資源的有效性。
            這種方式就是今天blog要寫(xiě)的主要內(nèi)容,我們可以看到std::auto_ptr作用范圍很小,只能對(duì)從堆上分配的對(duì)象進(jìn)行管理,假如對(duì)文件打開(kāi)句柄實(shí)行RAII,你也許會(huì)認(rèn)為再寫(xiě)個(gè)不就是了,但這樣只會(huì)造成源代碼里充滿了這些資源管理的類(lèi),這導(dǎo)致了一個(gè)嚴(yán)重的問(wèn)題,好的結(jié)構(gòu)在繁瑣的流暢前面變的難堪。
            那怎么樣對(duì)這個(gè)進(jìn)行泛化,從而能對(duì)比如從簡(jiǎn)單的指針釋放,文件句柄維護(hù),甚至相關(guān)的成員函數(shù)。我們來(lái)看下loki::socpeguard是怎么實(shí)現(xiàn)的:
            先看下基本的用法
            (1)? FILE* hFileOpen = fopen(....);
            (2)? LOKI_ON_BLOCK_EXIT(flose,hFileOpen);
            line2會(huì)在出LOKI_ON_BLOCK_EXIT域或程序異常結(jié)束時(shí)被調(diào)用,下面是對(duì)類(lèi)成員的調(diào)用
            void CTestObject::Create
            {
            ??? LOKI_ON_BLOCK_EXIT_OBJ(*this,FressResouce);
            ??? ...
            }
            同上面差不多,會(huì)在這個(gè)函數(shù)結(jié)束后或異常結(jié)束后調(diào)用類(lèi)成員的FreeResource.在正常流程結(jié)束后,可以通過(guò)調(diào)用Dismiss來(lái)防止對(duì)FreeResouce的調(diào)用,即類(lèi)似數(shù)據(jù)庫(kù)操作的commit操作。下面來(lái)分析下LOKI的實(shí)現(xiàn):
            從上面可以看到,RAII的是:
            1:構(gòu)造函數(shù)對(duì)資源的獲取
            2:稀構(gòu)函數(shù)對(duì)資源的釋放
            先來(lái)看下LoKi對(duì)上面那2個(gè)宏的定義
            #define LOKI_ON_BLOCK_EXIT????? Loki::ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) = Loki::MakeGuard

            #define LOKI_ON_BLOCK_EXIT_OBJ? Loki::ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) = Loki::MakeObjGuard
            上面的Loki::ScopeGuard是一個(gè)基類(lèi)的別名
            typedef const ScopeGuardImplBase& ScopeGuard;
            而LOKI_ANONYMOUS_VARIABLE(scopeGuard)用來(lái)我們產(chǎn)生唯一的名字,有時(shí)假如需要調(diào)用Dismiss的話,則需要自己去實(shí)現(xiàn)宏定義的內(nèi)容,這樣才能通過(guò)對(duì)象訪問(wèn)。Loki::MakeGuard或Loki::MakeObjGuard是用來(lái)產(chǎn)生對(duì)象的實(shí)際類(lèi)型的,下面是一個(gè)
            Loki::MakeGuard的例子:
            template <typename F, typename P1>
            inline ScopeGuardImpl1<F, P1> MakeGuard(F fun, P1 p1)
            {
            ??? return ScopeGuardImpl1<F, P1>::MakeGuard(fun, p1);
            }
            可以看到ScopeGuardImpl1<F, P1>是要產(chǎn)生的具體類(lèi)型,MakeGuard通過(guò)函數(shù)參數(shù)的數(shù)目來(lái)重載的,而MakeGuard此處的作用是要睡死了...-_-'',作用是利用函數(shù)自動(dòng)推導(dǎo)出參數(shù)的類(lèi)型,這樣就免去了指定ScopeGuardImpl1的類(lèi)型的麻煩,而
            ScopeGuardImpl1<F, P1>::MakeGuard(fun, p1);
            簡(jiǎn)單的返回對(duì)象的一個(gè)臨時(shí)變量,并assign給一個(gè)上面的一個(gè)scopeguard的實(shí)例,這里依賴一個(gè)C++的特性,臨時(shí)變量的聲命周期和通過(guò)他初始化的引用類(lèi)型的聲明周期是一致的。

            從上面可以看到Loki定義了一個(gè)ScopeGuardImplBase的基礎(chǔ)類(lèi)。這個(gè)類(lèi)定義了一個(gè)基本的方法Dismiss,以及相關(guān)的狀態(tài)。下面是loki中這個(gè)類(lèi)的定義
            class ScopeGuardImplBase
            {
            ??? ScopeGuardImplBase& operator =(const ScopeGuardImplBase&);
            ?protected:
            ??? ~ScopeGuardImplBase()
            ??? {}
            ??? ScopeGuardImplBase(const ScopeGuardImplBase& other) throw()
            ??????? : dismissed_(other.dismissed_)
            ??? {
            ??????? other.Dismiss();
            ??? }
            ??? template <typename J>
            ??? static void SafeExecute(J& j) throw()
            ??? {
            ??????? if (!j.dismissed_)
            ?????????? try
            ?????????? {
            ????????????? j.Execute();
            ?????????? }
            ?????????? catch(...)
            ?????????? {}
            ???? }
            ???????
            ???? mutable bool dismissed_;
            public:
            ???? ScopeGuardImplBase() throw() : dismissed_(false)
            ???? {}
            ???? void Dismiss() const throw()
            ???? {
            ???????? dismissed_ = true;
            ????? }
            };
            可以看到類(lèi)里面定義了上面所說(shuō)的一些屬性,其中SafeExecute用來(lái)提供子類(lèi)同一的資源釋放方法,并調(diào)用子類(lèi)的方法來(lái)具體操作,因?yàn)橄嚓P(guān)的函數(shù),變量都保存在具體的子類(lèi),可以看到這個(gè)函數(shù)使用了try catch,這里加這個(gè)的目的是,因?yàn)橘Y源釋放要在子類(lèi)的稀構(gòu)里被觸發(fā),而調(diào)用具體的方法是外面?zhèn)鬟M(jìn)來(lái)的,所以無(wú)法保證一定是異常安全的,而假如在稀構(gòu)里面異常的話,會(huì)導(dǎo)致程序的行為無(wú)法定義。
            下面具體來(lái)看下一個(gè)子類(lèi)的實(shí)現(xiàn):
            template <typename F, typename P1>
            class ScopeGuardImpl1 : public ScopeGuardImplBase
            {
            public:
            ??? static ScopeGuardImpl1<F, P1> MakeGuard(F fun, P1 p1)
            ??? {
            ??????? return ScopeGuardImpl1<F, P1>(fun, p1);
            ??? }
            ??? ~ScopeGuardImpl1() throw()
            ??? {
            ??????? SafeExecute(*this);
            ??? }
            ??? void Execute()
            ??? {
            ??????? fun_(p1_);
            ??? }
            protected:
            ??? ScopeGuardImpl1(F fun, P1 p1) : fun_(fun), p1_(p1)
            ??? {}
            ??? F fun_;
            ??? const P1 p1_;
            };
            在LoKi里面可以看到很多類(lèi)似ScopeGuardImpl1的定義,比如ScopeGuardImpl0,
            ScopeGuardImpl2,可以發(fā)現(xiàn)最后面的數(shù)字表示具體參數(shù)的數(shù)目。
            可以看到上面所說(shuō)的MakeGuard的定義,以及對(duì)基類(lèi)方法的調(diào)用,可以看到構(gòu)造函數(shù)接收的類(lèi)型,一個(gè)函數(shù)對(duì)象,和一些參數(shù)對(duì)象,并保存,對(duì)于成員函數(shù)的scopeguard,LoKi定義了1些相似的類(lèi),主要是增加了對(duì)象的引用,還有就是函數(shù)的調(diào)用方式上。
            上面可以看到參數(shù)是通過(guò)值的方式來(lái)保存的而不是通過(guò)引用。而且是const屬性的,下面是相關(guān)的分析。
            1:通過(guò)傳值的方式,從而避免了異常拋出時(shí),可能引用的對(duì)象被稀構(gòu)
            2:加const屬性,從而保證了在func需要參數(shù)是reference時(shí)而保存的參數(shù)確是非const時(shí)產(chǎn)生相應(yīng)的編譯錯(cuò)誤,因?yàn)閷?duì)reference傳人const non-reference形式是錯(cuò)誤的。
            而對(duì)于1的方式,存在的一種問(wèn)題是假如操作的fun需要傳入引用,那傳進(jìn)去的值就無(wú)法在釋放的函數(shù)中被改變,而2是對(duì)這種的一種類(lèi)似契約似的編程,Loki 提供的方法是通過(guò)一個(gè)中間對(duì)象來(lái)保存操作參數(shù)的引用,并賦予這個(gè)對(duì)象自動(dòng)轉(zhuǎn)換功能。下面是這個(gè)類(lèi)的定義:
            template <class T>
            class RefToValue
            {??
            public:
            ??? RefToValue(T& ref) : ref_(ref)
            ??? {}
            ??? RefToValue(const RefToValue& rhs) : ref_(rhs.ref_)
            ??? {}
            ??? operator T& () const
            ??? {
            ??????? return ref_;
            ??? }
            private:
            ??? // Disable - not implemented
            ??? RefToValue();
            ??? RefToValue& operator=(const RefToValue&);
            ???????
            ??? T& ref_;
            };
            可以很清楚的看到類(lèi)的實(shí)現(xiàn),下面是一個(gè)工具類(lèi)
            template <class T>
            inline RefToValue<T> ByRef(T& t)
            {
            ???? return RefToValue<T>(t);
            }
            下面給個(gè)具體的例子,假如
            template<typename _Ty>
            void SAFEDELETE(_Ty*& ptr)
            {
            ?? if (NULL != ptr)
            ????? delete ptr;
            ?? ptr = NULL;
            }

            char* ptr = new char;
            ?
            {
            ??? LOKI_ON_BLOCK_EXIT(SAFEDELETE<char>,Loki::ByRef(ptr));
            }
            ?
            if (NULL == ptr)
            ? std::cout << "NULL" << std::endl;
            基本上就這么多了,sleep去了
            ??????????????????????????????????????????????????? alex_yuu

            posted on 2007-02-11 15:55 agerlis 閱讀(1402) 評(píng)論(3)  編輯 收藏 引用

            評(píng)論

            # re: 編寫(xiě)異常安全的代碼(loki::scopeguard) 2007-02-11 15:56 agerlis
            請(qǐng)問(wèn),怎么設(shè)置背景色?  回復(fù)  更多評(píng)論
              

            # re: 編寫(xiě)異常安全的代碼(loki::scopeguard) 2007-02-12 16:13 mc
            不錯(cuò),把Loki::ScopeGuard介紹的比較透徹了:)  回復(fù)  更多評(píng)論
              

            # re: 編寫(xiě)異常安全的代碼(loki::scopeguard) 2007-05-28 16:40 candy
            看到這些代碼我就暈了,厲害啊,我比較討厭編程。。嘿嘿,我是龔芳萍。  回復(fù)  更多評(píng)論
              


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            四虎久久影院| 青青热久久国产久精品| 国内精品久久久久影院日本| 久久久久久亚洲精品成人| 99久久精品这里只有精品| 欧美激情一区二区久久久| 久久狠狠高潮亚洲精品| 亚洲Av无码国产情品久久| 国产综合久久久久| 伊人久久精品线影院| 欧美丰满熟妇BBB久久久| 99久久精品无码一区二区毛片| 久久精品国产亚洲αv忘忧草 | 亚洲国产成人久久精品影视| 伊人久久大香线蕉精品不卡| 日本精品久久久久中文字幕8 | 久久精品无码一区二区三区日韩 | 亚洲国产精品久久久久| 久久er99热精品一区二区| 青青久久精品国产免费看| 国产精品热久久毛片| 青青草国产精品久久久久| 亚洲狠狠婷婷综合久久久久| 一级a性色生活片久久无| 久久亚洲精品无码播放| 久久精品无码一区二区日韩AV| 麻豆精品久久久一区二区| 97久久超碰国产精品旧版| 久久大香香蕉国产| 久久精品国产亚洲av日韩| 午夜人妻久久久久久久久| 久久伊人精品一区二区三区| 国产精品久久新婚兰兰| 久久笫一福利免费导航| 中文字幕精品久久| 久久久久国产精品人妻| 狠狠精品久久久无码中文字幕| 久久综合亚洲色HEZYO社区| 亚洲中文字幕久久精品无码喷水| 久久久SS麻豆欧美国产日韩| 日本久久久久亚洲中字幕 |