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

            天下

            記錄修行的印記

            C++ RAII

             

            C++ RAII

                RAII是resource acquisition 
            is initialization的縮寫,意為“資源獲取即初始化”。它是C++之父Bjarne Stroustrup提出的設(shè)計(jì)理念,其核心是把資源和對象的生命周期綁定,對象創(chuàng)建獲取資源,對象銷毀釋放資源。在RAII的指導(dǎo)下,C++把底層的資源管理問題提升到了對象生命周期管理的更高層次。
                說起來,RAII的含義倒也不算復(fù)雜。用白話說就是:在類的構(gòu)造函數(shù)中分配資源,在析構(gòu)函數(shù)中釋放資源。這樣,當(dāng)一個(gè)對象創(chuàng)建的時(shí)候,構(gòu)造函數(shù)會(huì)自動(dòng)地被調(diào)用;而當(dāng)這個(gè)對象被釋放的時(shí)候,析構(gòu)函數(shù)也會(huì)被自動(dòng)調(diào)用。于是乎,一個(gè)對象的生命期結(jié)束后將會(huì)不再占用資源,資源的使用是安全可靠的。
            C
            ++ RAII體現(xiàn)出了簡潔、安全、實(shí)時(shí)的特點(diǎn):

            1.概念簡潔性:讓資源(包括內(nèi)存和非內(nèi)存資源)和對象的生命周期綁定,資源類的設(shè)計(jì)者只需用在類定義內(nèi)部處理資源問題,提高了程序的可維護(hù)性
            2.類型安全性:通過資源代理對象包裝資源(指針變量),并利用運(yùn)算符重載提供指針運(yùn)算方便使用,但對外暴露類型安全的接口
            3.異常安全性:棧語義保證對象析構(gòu)函數(shù)的調(diào)用,提高了程序的健壯性
            4.釋放實(shí)時(shí)性:和GC相比,RAII達(dá)到了和手動(dòng)釋放資源一樣的實(shí)時(shí)性,因此可以承擔(dān)底層開發(fā)的重任

            也許你還在驚訝RAII如此簡單的時(shí)候,關(guān)于RAII的主要內(nèi)容已經(jīng)介紹完了。簡單不意味著簡陋,在我看來RAII雖然不像GC一樣,是一套具體的機(jī)制,但它蘊(yùn)含的對象與資源關(guān)系的哲學(xué)深度的理解卻使得我對Bjarne Stroustrup肅然起敬!

            最后,不得不提醒RAII的理念固然簡單,不過在具體實(shí)現(xiàn)的時(shí)候仍有需要小心的地方。比如對于STL的auto_ptr,可以視為資源的代理對象,auto_ptr對象間的賦值是一個(gè)需要特別注意的地方。簡單說來資源代理對象間賦值的語義不滿足“賦值相等”,其語義是資源管理權(quán)的轉(zhuǎn)移。

            什么是“賦值相等”呢?比如:

            int a;  int b = 10;  a = b; //這句話執(zhí)行后 a == b 但對于資源代理對象,這是不滿足的,比如:

            auto_ptr
            <int> a(null);  auto_ptr<int> b(new int(123));  a = b; //這句話執(zhí)行后a != b,賦值的語義是b把資源的管理權(quán)交給了a 

            auto_ptr是這樣一種指針:它是“它所指向的對象”的擁有者。這種擁有具有唯一性,即一個(gè)對象只能有一個(gè)擁有者,嚴(yán)禁一物二主。當(dāng)auto_ptr指針被摧毀時(shí),它所指向的對象也將被隱式銷毀,即使程序中有異常發(fā)生,auto_ptr所指向的對象也將被銷毀。


            關(guān)于auto_ptr的幾種注意事項(xiàng):
            1、auto_ptr不能共享所有權(quán)。
            2、auto_ptr不能指向數(shù)組
            3、auto_ptr不能作為容器的成員。
            4、不能通過賦值操作來初始化auto_ptr
            std::auto_ptr
            <int> p(new int(42));     //OK
            std::auto_ptr<int> p = new int(42);    //ERROR
            這是因?yàn)閍uto_ptr 的構(gòu)造函數(shù)被定義為了explicit
            5、不要把a(bǔ)uto_ptr放入容器

            下面便是在C
            ++中實(shí)現(xiàn)RAII的典型代碼:
            class file
            {
            public:
                file(
            string const& name) {
                    m_fileHandle
            =fopen(name.cstr());
                }
                
            ~file() {
                    fclose(m_fileHandle);
                }
                
            //
            private:
                handle m_fileHandle;
            }

            很典型的“在構(gòu)造函數(shù)里獲取,在析構(gòu)函數(shù)里釋放”。如果我寫下代碼:   
            void fun1() {
                file myfile(
            "my.txt");
                 
            //操作文件
            //此處銷毀對象,調(diào)用析構(gòu)函數(shù),釋放資源
            當(dāng)函數(shù)結(jié)束時(shí),局部對象myfile的生命周期也結(jié)束了,析構(gòu)函數(shù)便會(huì)被調(diào)用,資源會(huì)得到釋放。而且,如果函數(shù)中的代碼拋出異常,那么析構(gòu)函數(shù)也會(huì)被調(diào)用,資源同樣會(huì)得到釋放。所以,在RAII下,不僅僅資源安全,也是異常安全的。

            但是,在如下的代碼中,資源不是安全的,盡管我們實(shí)現(xiàn)了RAII:
            void fun2() {
                file pfile
            =new file("my.txt");
                 
            //操作文件
            }
            因?yàn)槲覀冊诙焉蟿?chuàng)建了一個(gè)對象(通過new),但是卻沒有釋放它。我們必須運(yùn)用delete操作符顯式地加以釋放:
            void fun3() {
                file pfile
            =new file("my.txt");
                 
            //操作文件
                    delete pfile;
            }
            否則,非但對象中的資源得不到釋放,連對象本身的內(nèi)存也得不到回收。(將來,C
            ++的標(biāo)準(zhǔn)中將會(huì)引入GC(垃圾收集),但正如下面分析的那樣,GC依然無法確保資源的安全)。
            現(xiàn)在,在fun3(),資源是安全的,但卻不是異常安全的。因?yàn)橐坏┖瘮?shù)中拋出異常,那么delete pfile;這句代碼將沒有機(jī)會(huì)被執(zhí)行。

            C
            ++領(lǐng)域的諸位大牛們告誡我們:如果想要在沒有GC的情況下確保資源安全和異常安全,那么請使用智能指針:
            void fun4() {
                auto_ptr
            <file> spfile(new file("my.txt"));
                 
            //操作文件
            //此處,spfile結(jié)束生命周期的時(shí)候,會(huì)釋放(delete)對象
            那么,智能指針又是怎么做到的呢?下面的代碼告訴你其中的把戲(關(guān)于智能指針的更進(jìn)一步的內(nèi)容,請參考std::auto_ptr,boost或shared_ptr的智能指針)。
            也就是說,智能指針通過RAII來確保內(nèi)存資源的安全,也間接地使得對象上的RAII得到實(shí)施。不過,這里的RAII并不是十分嚴(yán)格:對象(所占的內(nèi)存也是資源)的創(chuàng)建(資源獲取)是在構(gòu)造函數(shù)之外進(jìn)行的。廣義上,我們也把它劃歸RAII范疇。
            但是,Matthew Wilson在《Imperfect C
            ++》一書中,將其獨(dú)立出來,稱其為RRID(Resource Release Is Destruction)。
            RRID的實(shí)施需要在類的開發(fā)者和使用者之間建立契約,采用相同的方法獲取和釋放資源。比如,如果在shared_ptr構(gòu)造時(shí)使用malloc(),便會(huì)出現(xiàn)問題,因?yàn)閟hared_ptr是通過delete釋放對象的。

            posted on 2011-03-22 14:25 天下 閱讀(9428) 評論(0)  編輯 收藏 引用 所屬分類: C/C++C++必殺技法

            <2011年9月>
            28293031123
            45678910
            11121314151617
            18192021222324
            2526272829301
            2345678

            導(dǎo)航

            統(tǒng)計(jì)

            常用鏈接

            留言簿(4)

            隨筆分類(378)

            隨筆檔案(329)

            鏈接

            最新隨筆

            搜索

            最新評論

            77777亚洲午夜久久多喷| 久久久久久亚洲精品成人| 国产激情久久久久影院老熟女免费 | 亚洲狠狠婷婷综合久久蜜芽| 久久综合久久自在自线精品自| 国产成人久久AV免费| 久久久久99精品成人片| 国产69精品久久久久9999APGF | 久久综合视频网| 久久亚洲私人国产精品vA| 久久久久久久久久免免费精品| 精品国产一区二区三区久久久狼| 国产女人aaa级久久久级| 久久久久亚洲av无码专区喷水 | 国产99久久久国产精免费| 久久久精品人妻一区二区三区蜜桃| 久久综合久久综合久久综合| 久久久久久久精品成人热色戒| 色综合合久久天天综合绕视看| 新狼窝色AV性久久久久久| 色偷偷88欧美精品久久久| 国产精品xxxx国产喷水亚洲国产精品无码久久一区 | 久久99热这里只频精品6| 青青青伊人色综合久久| 午夜精品久久久久久久久| 中文字幕精品无码久久久久久3D日动漫| 丁香狠狠色婷婷久久综合| 亚洲精品国产字幕久久不卡| 久久天天躁夜夜躁狠狠躁2022| 久久久久成人精品无码| 91麻精品国产91久久久久| 色综合久久精品中文字幕首页 | 久久棈精品久久久久久噜噜| 亚洲狠狠婷婷综合久久久久| 国内精品久久久久影院亚洲| 久久久久亚洲精品无码网址| 久久精品国产亚洲AV不卡| 久久黄色视频| 亚洲一级Av无码毛片久久精品| 合区精品久久久中文字幕一区| 亚洲欧洲中文日韩久久AV乱码|