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

            兔子的技術(shù)博客

            兔子

               :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
              202 Posts :: 0 Stories :: 43 Comments :: 0 Trackbacks

            留言簿(10)

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            原文:http://blog.csdn.net/huntrose/archive/2008/11/18/3326388.aspx

            指針 是C++中不得不談的一個(gè)話題,或許我還不是很能熟練的掌握指針以及我所要討論的引用計(jì)數(shù)型指針的全部,但是還是有那么些迫不及待想要表達(dá)一下。

            指針 pointer 是 資源泄漏 resource leak 的根源(當(dāng)然可能還有其他一些什么東西,在我的映像中 異常 仿佛也會(huì)造成資源泄漏)

            最簡(jiǎn)單的一個(gè)資源泄漏的例子就是new和delete這樣的動(dòng)態(tài)內(nèi)存分配算子沒有正確使用造成的:

             

            struct A {

                A()  { printf(
            "A Constructor!"); }

                
            ~A() { printf("A Destructor!"); }

            };

            void area()

            {

                A 
            *= new A();

            }


             執(zhí)行完 area() 后,自然是只有A構(gòu)造的消息,而A的析構(gòu)卻不見影蹤。這里我們?cè)陔x開了area作用域后,我們就無法對(duì)p所指向之資源進(jìn)行操作,A的實(shí)例就會(huì)被懸掛在內(nèi)存的某處得不到清理。一個(gè)形象點(diǎn)的比方就像人類發(fā)送的宇宙衛(wèi)星失去了動(dòng)力以及和地球的聯(lián)系,無法收回,就變成了宇宙垃圾~

             

            然而利用對(duì)象來管理資源是一個(gè)很好的辦法,因?yàn)閷?duì)象的實(shí)例本身在脫離作用域后會(huì)自動(dòng)清理,就像這樣

             

            class A_holder {

            public:

                expilict A_holder(A
            * p = NULL)

                :ptr(p) {}

             

                
            ~A_holder()

            {

                
            if (ptr)

                   delete ptr;

            }

            private:

                A
            * ptr;

            };

             

            如此,我們?cè)赼rea里面把資源的管理權(quán)力交給A_holder,就像下面這樣

             

            void area()

            {

                A_holder ah(
            new A);

            }

             

            這樣,ah在離開area后會(huì)自動(dòng)調(diào)用其析構(gòu)函數(shù),就達(dá)到了自動(dòng)管理該資源的目的。

            利用C++的類的實(shí)例離開作用域會(huì)自動(dòng)調(diào)用其析構(gòu)函數(shù)的機(jī)制,可以比較方便的管理資源,但是在使用普通指針的情況下會(huì)存在多個(gè)指針指向同一對(duì)象的情況。

             

            void multi_point()

            {

                
            int a;

                
            int *p1,*p2;

             

                p1 
            = &a;

                p2 
            = &a;

            }

             

            實(shí)際的指針指向情況應(yīng)該是這樣

            p1 -à a ß- p2

             

            這里就出現(xiàn)了一個(gè)問題,我們想取消p1的時(shí)候可能會(huì)出現(xiàn)兩種語義:

            1、 將p1和其指向的對(duì)象一起刪除,這樣p2也就不可以繼續(xù)對(duì)a進(jìn)行使用。但是往往p2的使用者不會(huì)知道a已經(jīng)刪除,則出現(xiàn)了錯(cuò)誤。

            2、 將p1與其指向的對(duì)象解除關(guān)系,這樣p2還可以對(duì)a進(jìn)行使用。

             

            對(duì)于普通的delete操作,實(shí)現(xiàn)的是第一種情況,這樣通過p2對(duì)a進(jìn)行訪問必然會(huì)造成致命的錯(cuò)誤。

            在實(shí)現(xiàn)holder類的時(shí)候應(yīng)該也考慮到第二種情況,如果有另外一個(gè)holder也指向這個(gè)資源,其中一個(gè)holder銷毀,另外一個(gè)holder還可能會(huì)使用到它們共同指向的那個(gè)資源。于是,holder的作用就不僅僅是單單的持有和施放資源,還應(yīng)該處理有多少個(gè)對(duì)其hold資源的引用(即引用計(jì)數(shù)),并且在引用計(jì)數(shù)降為0時(shí)真正的銷毀資源實(shí)體。

             

            如此,一個(gè)行為類似指針(有->,*操作符)的智能指針出現(xiàn),它管理賦予其資源的引用計(jì)數(shù),也管理該資源的生死存亡。

            一個(gè)簡(jiǎn)單的Reference Count Smart Pointer的實(shí)現(xiàn)如下:

             



               #ifndef COUNTED_PTR_HPP

               
            #define COUNTED_PTR_HPP

             

               
            /*class for counted reference semantics

                *-deletes the object to which it refers when the last CountedPtr

                * that refers to it is destroyed

                
            */

               template 
            <class T>

               
            class CountedPtr {

                 
            private:

                   T
            * ptr;        // pointer to the value

                   
            long* count;   // shared number of owners

             

                 
            public:

                   
            //initialize pointer with existing pointer

                   
            //-requires that the pointer p is a return value of new

                   
            explicit CountedPtr (T* p=0)

                    : ptr(p), count(
            new long(1)) {

                   }

             

                   
            //copy pointer (one more owner)

                   CountedPtr (
            const CountedPtr<T>& p) throw()

                    : ptr(p.ptr), count(p.count) {

                       
            ++*count;

                   }

             

                   
            //destructor (delete value if this was the last owner)

                   
            ~CountedPtr () throw() {

                       dispose();

                   }

             

                   
            //assignment (unshare old and share new value)

                   CountedPtr
            <T>& operator= (const CountedPtr<T>& p) throw() {

                       
            if (this != &p) {

                           dispose();

                           ptr 
            = p.ptr;

                           count 
            = p.count;

                           
            ++*count;

                       }

                       
            return *this;

                   }

             

                   
            //access the value to which the pointer refers

                   T
            & operator*() const throw() {

                       
            return *ptr;

                   }

                   T
            * operator->() const throw() {

                       
            return ptr;

                   }

             

                 
            private:

                   
            void dispose() {

                       
            if (--*count == 0) {

                            delete count;

                            delete ptr;

                       }

                   }

               };

             

               
            #endif /*COUNTED_PTR_HPP*/

             

             

            由此,一個(gè)新的問題出現(xiàn)了!循環(huán)引用!

             

            這樣的一個(gè)引用計(jì)數(shù)型智能指針目的是為了防止資源泄漏,但是只需要一個(gè)很小巧的代碼就可以讓這樣的初衷化為烏有……

             



            class A

            {

            public:

                A() {cout
            <<"A CON"<<endl;}

                
            ~A() {cout<<"A DES"<<endl;}

                

                
            void hold(CountedPtr<A> ptr)

                {

                   m_ptr 
            = ptr; 

                }

            private:

                CountedPtr
            <A> m_ptr;

            };

             

            void self_cir_area()

            {

                CountedPtr
            <A> pA(new A());

                pA
            ->hold(pA);

            }

             

             

            可以看見,一個(gè)對(duì)象A中有一個(gè)引用計(jì)數(shù)型智能指針,這樣的設(shè)計(jì)可能會(huì)很常見(指向自身類型的結(jié)構(gòu)體——鏈表)

            但是,當(dāng)自身循環(huán)引用發(fā)生的時(shí)候會(huì)怎么樣呢? 下面就來看看這么兩句代碼

             

             

                CountedPtr<A> pA(new A());

             

             

            這里我們新建一個(gè)資源,并且把這個(gè)資源的管理權(quán)移交給pA這個(gè)引用計(jì)數(shù)型智能指針對(duì)象管理。如此,pA中的引用計(jì)數(shù)被初始化為1。

             

                pA->hold(pA);

             

            這里,我們把pA對(duì)象傳入給實(shí)例化的A對(duì)象中的引用計(jì)數(shù)型智能指針m_ptr,m_ptr執(zhí)行這樣的一個(gè)成員函數(shù):

             



                   
            //assignment (unshare old and share new value)

                   CountedPtr
            <T>& operator= (const CountedPtr<T>& p) throw() {

                       
            if (this != &p) {

                           dispose();

                           ptr 
            = p.ptr;

                           count 
            = p.count;

                           
            ++*count;

                       }

                       
            return *this;

                   }

             

            因?yàn)檫@里很明顯不是自身賦值,A中的m_ptr和pA不是同一個(gè)對(duì)象,所以進(jìn)入if結(jié)構(gòu)中調(diào)用下面的內(nèi)容。dispose是用作清理,因?yàn)閙_ptr并沒有指向任何東西,所以第一個(gè)函數(shù)并沒有真正的意義。

            然后

             

            m_ptr.ptr = pA.ptr;

            m_ptr.count 
            = pA.count;

            ++(*m_ptr.count);  //(*pA.count)也被++

             

            到此,pA的引用計(jì)數(shù)為2

             

            嗯,下面就pA這個(gè)對(duì)象理所當(dāng)然的離開了作用域,調(diào)用其析構(gòu)函數(shù):

             



                   
            ~CountedPtr () throw() {

                       dispose();

                   }

             
            噢,是一個(gè)轉(zhuǎn)向,調(diào)用其private成員函數(shù)dispose():

             

            void dispose() {

                       
            if (--*count == 0) {

                            delete count;

                            delete ptr;

                       }

                   }


            很簡(jiǎn)單,將引用計(jì)數(shù)-1,由2變成1,不為0,所以if結(jié)構(gòu)內(nèi)的語句不被執(zhí)行。

            由此,我們又制造了一個(gè)完美的太空垃圾……

             

            這樣的循環(huán)引用問題應(yīng)該是在設(shè)計(jì)的過程中就應(yīng)該避免的,如果用UML語言描述

            A中持有一個(gè) 引用計(jì)數(shù)型智能指針 的語義就是 這個(gè) 持有關(guān)系 是需要在 A消失的時(shí)候所持有的對(duì)象也隨之消失(這正是智能指針的作用,在脫離作用域自動(dòng)清除其持有的資源)。如此就構(gòu)成了 組合 關(guān)系。如果要表示 聚合 關(guān)系,即有 部分-整體 關(guān)系但是部分不隨整體的消失而消失,這就不是 智能指針 所表達(dá)的語義。

             

            還有可能遇見的循環(huán)引用就是 A1 持有 A2, A2 持有 A1 的情況……

            這樣A1,A2中對(duì)雙方的引用計(jì)數(shù)都是2,當(dāng)一方“銷毀”的時(shí)候,雙方的應(yīng)用計(jì)數(shù)都變?yōu)?,實(shí)際上并沒有銷毀任何東西,制造了兩個(gè)完美無暇的太空垃圾~

             

            這里又引發(fā)出一個(gè)問題,這樣的資源泄漏問題實(shí)際上還是由程序員自身引起的。

            C++之所以是一個(gè)很容易出錯(cuò)的語言,很大一部分在于其資源的管理權(quán)力全權(quán)交給了程序員。這樣的權(quán)力到底是造福了程序員還是迷惑了程序員呢?

             

            這里我卻想起了蜘蛛俠中的一句名言: “一個(gè)人能力有多大,責(zé)任就有多大!”

             

            對(duì)C++中指針的指責(zé)不是一天兩天了,其易錯(cuò)性無可厚非,但是它卻給了你其他語言無法給你的能力!這就是我的觀點(diǎn),你能力有這么大,你就有責(zé)任來治理好這些資源。而非一再推卸責(zé)任。如果真的是要推卸責(zé)任,也就應(yīng)該去選擇其他那些剝奪你的能力而減少你的責(zé)任的語言,因?yàn)槟阌羞x擇權(quán)!就像說英語和中文一樣,并沒有哪個(gè)人在強(qiáng)迫你,不是么?熱愛C++是一種態(tài)度,對(duì)一個(gè)語言的利弊都了然于心,了解其可以做什么不可以做什么,怎樣才可以更好的使用它來做什么,才能更好的使用它。更何況,there are rarely things that are not possible in C++

             

            本文來自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/huntrose/archive/2008/11/18/3326388.aspx

            posted on 2009-09-04 11:22 會(huì)飛的兔子 閱讀(198) 評(píng)論(0)  編輯 收藏 引用 所屬分類: C++及開發(fā)環(huán)境
            69久久夜色精品国产69| 欧美久久久久久午夜精品| 久久久久综合国产欧美一区二区| 一本色道久久综合狠狠躁| 欧美性猛交xxxx免费看久久久| 成人a毛片久久免费播放| 久久线看观看精品香蕉国产| 国产精品美女久久久久| 国产成年无码久久久久毛片| 99久久婷婷国产综合亚洲| 国产99精品久久| 很黄很污的网站久久mimi色| 国内精品久久久久久久久| 精品国产热久久久福利| 久久国产精品二国产精品 | 开心久久婷婷综合中文字幕| 久久精品二区| 国产精品久久久久久久app| 中文字幕乱码人妻无码久久| 久久久久人妻精品一区| 亚洲国产天堂久久综合网站| 欧美久久亚洲精品| 人妻少妇久久中文字幕| 亚洲国产成人久久综合一| 亚洲人AV永久一区二区三区久久 | 久久久精品免费国产四虎| 国产精品国色综合久久| 久久激情亚洲精品无码?V| 一本一道久久综合狠狠老| 久久亚洲国产精品一区二区| 久久天天躁狠狠躁夜夜2020老熟妇 | 久久99精品综合国产首页| 国产精品成人久久久久三级午夜电影 | 久久综合香蕉国产蜜臀AV| 99久久国产综合精品成人影院| 色婷婷久久综合中文久久一本| 少妇高潮惨叫久久久久久| 国内精品欧美久久精品| 久久亚洲欧美国产精品| 久久受www免费人成_看片中文| 久久久国产乱子伦精品作者|