• <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>
            空の軌跡
            ---萬物歸宗,世界本空
            posts - 0,  comments - 0,  trackbacks - 0
            假設(shè)我們和一個(gè)投資(例如,股票,債券等)模型庫(kù)一起工作,各種各樣的投資形式從一個(gè)根類 Investment 派生出來:

            class Investment { ... }; // root class of hierarchy of
            // investment types


              進(jìn)一步假設(shè)這個(gè)庫(kù)使用了通過一個(gè) factory 函數(shù)為我們提供特定 Investment 對(duì)象的方法:

            Investment* createInvestment();   // return ptr to dynamically allocated
            // object in the Investment hierarchy;
            // the caller must delete it
            // (parameters omitted for simplicity)

              通過注釋指出,當(dāng) createInvestment 函數(shù)返回的對(duì)象不再使用時(shí),由 createInvestment 的調(diào)用者負(fù)責(zé)刪除它。那么,請(qǐng)考慮,寫一個(gè)函數(shù) f 來履行以下職責(zé):

            void f()
            {
            Investment *pInv = createInvestment(); // call factory function
            ... // use pInv
            delete pInv;   // release object
            }


              這個(gè)看上去沒問題,但是有幾種情形會(huì)造成 f 在刪除它從 createInvestment 得到的 investment 對(duì)象時(shí)失敗。有可能在這個(gè)函數(shù)的 "..." 部分的某處有一個(gè)提前出現(xiàn)的 return 語句。如果這樣一個(gè) return 執(zhí)行了,控制流程就再也無法到達(dá) delete 語句。還可能發(fā)生的一個(gè)類似情況是如果 createInvestment 的使用和刪除在一個(gè)循環(huán)里,而這個(gè)循環(huán)以一個(gè) continuegoto 語句提前退出。還有,"..." 中的一些語句可能拋出一個(gè)異常。如果這樣,控制流程不會(huì)再到達(dá)那個(gè) delete。無論那個(gè) delete 被如何跳過,我們泄漏的不僅僅是容納 investment 對(duì)象的內(nèi)存,還包括那個(gè)對(duì)象持有的任何資源。

              當(dāng)然,小心謹(jǐn)慎地編程能防止這各種錯(cuò)誤,但考慮到這些代碼可能會(huì)隨著時(shí)間的流逝而發(fā)生變化。為了對(duì)軟件進(jìn)行維護(hù),一些人可能會(huì)在沒有完全把握對(duì)這個(gè)函數(shù)的資源管理策略的其它部分的影響的情況下增加一個(gè) returncontinue 語句。尤有甚者,f 的 "..." 部分可能調(diào)用了一個(gè)從不慣于拋出異常的函數(shù),但是在它被“改良”后突然這樣做了。依賴于 f 總能到達(dá)它的 delete 語句根本靠不住。

              為了確保 createInvestment 返回的資源總能被釋放,我們需要將那些資源放入一個(gè)類中,這個(gè)類的析構(gòu)函數(shù)在控制流程離開 f 的時(shí)候會(huì)自動(dòng)釋放資源。實(shí)際上,這只是本文介紹的觀念的一半:將資源放到一個(gè)對(duì)象的內(nèi)部,我們可以依賴 C++ 的自動(dòng)地調(diào)用析構(gòu)函數(shù)來確保資源被釋放。(過一會(huì)兒我們還要介紹本文觀念的另一半。)

              許多資源都是動(dòng)態(tài)分配到堆上的,并在一個(gè)單獨(dú)的塊或函數(shù)內(nèi)使用,而且應(yīng)該在控制流程離開那個(gè)塊或函數(shù)的時(shí)候釋放。標(biāo)準(zhǔn)庫(kù)的 auto_ptr 正是為這種情形量體裁衣的。auto_ptr 是一個(gè)類似指針的對(duì)象(一個(gè)智能指針),它的析構(gòu)函數(shù)自動(dòng)在它指向的東西上調(diào)用 delete。下面就是如何使用 auto_ptr 來預(yù)防 f 的潛在的資源泄漏:

            void f()
            {
            std::auto_ptr<Investment> pInv(createInvestment()); // call factory
            // function
            ... // use pInv as
            // before
            } // automatically
            // delete pInv via
            // auto_ptr’s dtor


              這個(gè)簡(jiǎn)單的例子示范了使用對(duì)象管理資源的兩個(gè)重要的方面:

              獲得資源后應(yīng)該立即移交給資源管理對(duì)象。如上,createInvestment 返回的資源被用來初始化即將用來管理它的 auto_ptr。實(shí)際上,因?yàn)楂@取一個(gè)資源并在同一個(gè)語句中初始化資源管理對(duì)象是如此常見,所以使用對(duì)象管理資源的觀念也常常被稱為 Resource Acquisition Is Initialization (RAII)。有時(shí)被獲取的資源是被賦值給資源管理對(duì)象的,而不是初始化它們,但這兩種方法都是在獲取資源的同時(shí)就立即將它移交給資源管理對(duì)象。

              資源管理對(duì)象使用它們的析構(gòu)函數(shù)確保資源被釋放。因?yàn)楫?dāng)一個(gè)對(duì)象被銷毀時(shí)(例如,當(dāng)一個(gè)對(duì)象離開其活動(dòng)范圍)會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù),無論控制流程是怎樣離開一個(gè)塊的,資源都會(huì)被正確釋放。如果釋放資源的動(dòng)作會(huì)引起異常拋出,事情就會(huì)變得棘手,不過,關(guān)于那些問題以后我將專題講解,所以不必?fù)?dān)心它。

              因?yàn)楫?dāng)一個(gè) auto_ptr 被銷毀的時(shí)候,會(huì)自動(dòng)刪除它所指向的東西,所以不要讓超過一個(gè)的 auto_ptr 指向同一個(gè)對(duì)象非常重要。如果發(fā)生了這種事情,那個(gè)對(duì)象就會(huì)被刪除超過一次,而且會(huì)讓你的程序通過捷徑進(jìn)入未定義行為。為了防止這個(gè)問題,auto_ptrs 具有不同尋常的特性:拷貝它們(通過拷貝構(gòu)造函數(shù)或者拷貝賦值運(yùn)算符)就是將它們置為空,拷貝的指針被設(shè)想為資源的唯一所有權(quán)。

            std::auto_ptr<Investment> // pInv1 points to the
            pInv1(createInvestment()); // object returned from
            // createInvestment

            std::auto_ptr<Investment> pInv2(pInv1); // pInv2 now points to the
            // object; pInv1 is now null

            pInv1 = pInv2; // now pInv1 points to the
            // object, and pInv2 is null


              這個(gè)奇怪的拷貝行為,增加了潛在的需求,就是通過 auto_ptrs 管理的資源必須絕對(duì)沒有超過一個(gè) auto_ptr 指向它們,這也就意味著 auto_ptrs 不是管理所有動(dòng)態(tài)分配資源的最好方法。例如,STL 容器要求其內(nèi)含物能表現(xiàn)出“正常的”拷貝行為,所以 auto_ptrs 的容器是不被允許的。

              相對(duì)于 auto_ptrs,另一個(gè)可選方案是一個(gè)引用計(jì)數(shù)智能指針(reference-counting smart pointer, RCSP)。一個(gè) RCSP 是一個(gè)智能指針,它能持續(xù)跟蹤有多少對(duì)象指向一個(gè)特定的資源,并能夠在不再有任何東西指向那個(gè)資源的時(shí)候刪除它。就這一點(diǎn)而論,RCSP 提供的行為類似于垃圾收集(garbage collection)。與垃圾收集不同的是,無論如何,RCSP 不能打破循環(huán)引用(例如,兩個(gè)沒有其它使用者的對(duì)象互相指向?qū)Ψ剑?BR>
              TR1 的 tr1::shared_ptr是一個(gè) RCSP,所以你可以這樣寫 f:

            void f()
            {
            ...

            std::tr1::shared_ptr<Investment>
            pInv(createInvestment()); // call factory function
            ...  // use pInv as before
            }    // automatically delete
            // pInv via shared_ptr’s dtor


              這里的代碼看上去和使用 auto_ptr 的幾乎相同,但是拷貝 shared_ptrs 的行為卻自然得多:

            void f()
            {
            ...

            std::tr1::shared_ptr<Investment> // pInv1 points to the
            pInv1(createInvestment());       // object returned from
                                             // createInvestment

            std::tr1::shared_ptr<Investment>  // both pInv1 and pInv2 now
            pInv2(pInv1);                     // point to the object

            pInv1 = pInv2; // ditto - nothing has
            // changed
            ...
            }  // pInv1 and pInv2 are
               // destroyed, and the
               // object they point to is
               // automatically deleted


              因?yàn)榭截?tr1::shared_ptrs 的工作“符合預(yù)期”,它們能被用于 STL 容器以及其它和 auto_ptr 的非正統(tǒng)的拷貝行為不相容的環(huán)境中。

              不要搞錯(cuò),本文不是關(guān)于 about auto_ptr,tr1::shared_ptr 或任何其它種類的智能指針。而是關(guān)于使用對(duì)象管理資源的重要性的。about auto_ptr 和 tr1::shared_ptr 僅僅是做這些事的對(duì)象的例子。(關(guān)于 tr1::shared_ptr 的更多信息,請(qǐng)參考 Item 14,18 和 54。)

              about auto_ptr 和 tr1::shared_ptr 都在它們的析構(gòu)函數(shù)中使用 delete,而不是 delete []。這就意味著將 about auto_ptr 或 tr1::shared_ptr 用于動(dòng)態(tài)分配的數(shù)組是個(gè)餿主意,可是,可悲的是,那居然可以編譯:

            std::auto_ptr<std::string>  // bad idea! the wrong
            aps(new std::string[10]);   // delete form will be used

            std::tr1::shared_ptr<int> spi(new int[1024]); // same problem


              你可能會(huì)吃驚地發(fā)現(xiàn) C++ 中沒有可用于動(dòng)態(tài)分配數(shù)組的類似 auto_ptr 或 tr1::shared_ptr 這樣的東西,甚至在 TR1 中也沒有。那是因?yàn)?vectorstring 幾乎總是能代替動(dòng)態(tài)分配數(shù)組。如果你依然覺得有可用于數(shù)組的類似 auto_ptr 和類似 tr1::shared_ptr 的類更好一些的話,可以去看看 Boost。在那里,你將高興地找到 boost::scoped_array 和 boost::shared_array 兩個(gè)類提供你在尋找的行為。 本 Item 的關(guān)于使用對(duì)象管理資源的指導(dǎo)間接表明:如果你手動(dòng)釋放資源(例如,使用 delete,而不使用資源管理類),你就是在自找麻煩。像 auto_ptr 和 tr1::shared_ptr 這樣的預(yù)制的資源管理類通常會(huì)使本文的建議變得容易,但有時(shí),你使用了一個(gè)資源,而這些預(yù)加工的類不能如你所愿地做事。如果碰上這種情況,你就需要精心打造你自己的資源管理類。那也并非困難得可怕,但它包含一些需要你細(xì)心考慮的微妙之處。

              作為最后的意見,我必須指出 createInvestment 的未加工指針的返回形式就是資源泄漏的請(qǐng)?zhí)驗(yàn)檎{(diào)用者忘記在他們?nèi)』貋淼闹羔樕险{(diào)用 delete 實(shí)在是太容易了。(即使他們使用一個(gè) auto_ptrtr1::shared_ptr 來完成 delete,他們?nèi)匀槐仨氂涀?createInvestment 的返回值存儲(chǔ)到智能指針對(duì)象中。)對(duì)付這個(gè)問題需要改變 createInvestment 的接口。

              Things to Remember

              ·為了防止資源泄漏,使用 RAII 對(duì)象,在 RAII 對(duì)象的構(gòu)造函數(shù)中獲得資源并在析構(gòu)函數(shù)中釋放它們。

              ·兩個(gè)通用的 RAII 是 tr1::shared_ptr 和 auto_ptr。tr1::shared_ptr 通常是更好的選擇,因?yàn)樗目截悤r(shí)的行為是符合直覺的。拷貝一個(gè) auto_ptr 是將它置為空。
            posted on 2005-10-29 21:14 空の軌跡 閱讀(89) 評(píng)論(0)  編輯 收藏 引用

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



            <2025年8月>
            272829303112
            3456789
            10111213141516
            17181920212223
            24252627282930
            31123456

            常用鏈接

            留言簿

            文章檔案

            好文連接

            搜索

            •  

            最新評(píng)論

            91麻精品国产91久久久久| 久久免费视频1| 99精品久久久久久久婷婷| 精品人妻伦九区久久AAA片69| 久久无码人妻精品一区二区三区| 国产美女亚洲精品久久久综合| 亚洲AV日韩精品久久久久久久| 国产精品内射久久久久欢欢 | 久久精品国产亚洲一区二区三区| 亚洲精品成人久久久| 一本一道久久精品综合| 国产aⅴ激情无码久久| 国内精品欧美久久精品| 久久99精品国产麻豆| 久久这里的只有是精品23| 91精品国产综合久久香蕉| 久久精品www人人爽人人| 久久天天躁狠狠躁夜夜躁2014| 久久99久久成人免费播放| 99久久婷婷国产综合亚洲| 日本久久久久亚洲中字幕| 久久天天婷婷五月俺也去| 久久亚洲中文字幕精品一区四| 中文字幕一区二区三区久久网站| avtt天堂网久久精品| 97久久超碰国产精品2021| 日韩精品久久无码人妻中文字幕| 久久久久亚洲国产| 伊人久久大香线蕉av不卡| 蜜桃麻豆WWW久久囤产精品| 久久人人添人人爽添人人片牛牛| 久久午夜综合久久| 久久久国产99久久国产一| 亚洲欧洲久久av| 久久久久久精品成人免费图片| 伊人色综合九久久天天蜜桃| 热久久最新网站获取| 午夜精品久久久久久久| 久久精品国产亚洲精品2020 | 伊人久久大香线焦综合四虎| 99久久无色码中文字幕|