• <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>
            隨筆-22  評(píng)論-7  文章-0  trackbacks-0
            Solmyr 的小品文系列之五:垃圾收集 轉(zhuǎn)自pchome
            午餐時(shí)間。

            zero 坐在餐桌前,機(jī)械的重復(fù)“夾菜 -> 咀嚼 -> 吞咽”的動(dòng)作序列,臉上用無(wú)形的大字寫(xiě)著:我心不在焉。在他的對(duì)面坐著 Solmyr ,慢條斯理的吃著他那份午餐,維持著他一貫很有修養(yǎng)的形象 ——— 或者按照 zero 這些熟悉他本質(zhì)的人的說(shuō)法:假象。

            “怎么了 zero ?胃口不好么?”,基本填飽肚子之后,Solmyr 覺(jué)得似乎應(yīng)該關(guān)心一下他的學(xué)徒了。

            “呃,沒(méi)什么,只是 …… Solmyr ,C++ 為什么不支持垃圾收集呢?(注:垃圾收集是一種機(jī)制,保證動(dòng)態(tài)分配了的內(nèi)存塊會(huì)自動(dòng)釋放,Java 等
            語(yǔ)言支持這一機(jī)制。)”

            Solmyr 嘆了口氣,用一種平靜的眼神盯著 zero :“是不是在 BBS 上和人吵 C++ 和 Java 哪個(gè)更好?而且吵輸了?我早告訴過(guò)你,這種爭(zhēng)論再無(wú)聊不過(guò)了。”

            “呃 …… 是”,zero 不得不承認(rèn) ——— Solmyr 的眼神雖然一點(diǎn)也不銳利,但是卻莫名其妙的讓 zero 產(chǎn)生了微微的恐懼感。

            “而且,誰(shuí)告訴你 C++ 不支持垃圾收集的?”

            “啊!Solmyr 你不是開(kāi)玩笑吧?!”

            “zero 你得轉(zhuǎn)變一下觀(guān)念。我問(wèn)你,C++ 支不支持可以動(dòng)態(tài)改變大小的數(shù)組?”

            “這 …… 好象也沒(méi)有吧?”

            “那 vector 是什么東西?”

            “呃 ……”

            “支持一種特性,并不是說(shuō)非得把這個(gè)特性加到語(yǔ)法里去,我們也可以選擇用現(xiàn)有的語(yǔ)言機(jī)制實(shí)現(xiàn)一個(gè)庫(kù)來(lái)支持這個(gè)特征。以垃圾收集為例,這里我們的任務(wù)是要保證每一個(gè)被動(dòng)態(tài)分配的內(nèi)存塊都能夠被釋放,也就是說(shuō) ……”,Solmyr 不知從哪里找出了一張紙、一支筆,寫(xiě)到:

            int* p = new int; // 1
            delete p; // 2

            “也就是說(shuō),對(duì)于每一個(gè) 1 ,我們要保證有一個(gè) 2 被調(diào)用,1 和 2 必須成對(duì)出現(xiàn)。我來(lái)問(wèn)你,C++ 中有什么東西是由語(yǔ)言本身保證一定成對(duì)出現(xiàn)的?”

            “……”,zero 露出了努力搜索記憶的表情,不過(guò)很明顯一無(wú)所獲。

            “提示一下,和類(lèi)的創(chuàng)建有關(guān)。”

            “哦!構(gòu)造函數(shù)與析構(gòu)函數(shù)!”

            “正確。可惜普通指針沒(méi)有構(gòu)造函數(shù)與析構(gòu)函數(shù),所以我們必須要寫(xiě)一個(gè)類(lèi)來(lái)加一層包裝,最簡(jiǎn)單的就象這樣:”

            class my_intptr
            {
            public:
            int* m_p;

            my_intptr(int* p){ m_p = p; }
            ~my_intptr(){ delete m_p; }
            };

            …………

            my_intptr pi(new int);
            *(pi.m_p) = 10;

            …………

            “這里我們可以放心的使用 my_intptr ,不用擔(dān)心內(nèi)存泄漏的問(wèn)題:一旦 pi 這個(gè)變量被銷(xiāo)毀,我們知道 pi.p 指向的內(nèi)存塊一定會(huì)被釋放。不過(guò)如果每次使用 my_intptr 都得去訪(fǎng)問(wèn)它的成員未免太麻煩了。為此,可以給這個(gè)類(lèi)加上重載的 * 運(yùn)算符:”

            class my_intptr
            {
            private:
            int* m_p;

            public:
            my_intptr(int* p){ m_p = p; }
            ~my_intptr(){ delete m_p; }

            int& operator*(){ return *m_p; }
            };

            …………

            my_intptr pi;
            *pi = 10;
            int a = *pi;

            …………

            “現(xiàn)在是不是看起來(lái) my_intptr 就像是一個(gè)真正的指針了?正因?yàn)槿绱耍@種技術(shù)被稱(chēng)為智能指針。現(xiàn)在我問(wèn)你,這個(gè)類(lèi)還缺少哪些東西?”

            zero 皺著眉頭,眼睛一眨一眨,看上去就像一臺(tái)慢速電腦正在辛苦的往它的硬盤(pán)上拷貝文件。良久,zero 抬起頭來(lái),不太確定的說(shuō):“是不是還缺少一個(gè)拷貝構(gòu)造函數(shù)和一個(gè)賦值運(yùn)算符?”

            “說(shuō)說(shuō)為什么。”,Solmyr 顯然不打算就這樣放過(guò) zero。

            “因?yàn)?…… 我記得沒(méi)錯(cuò)的話(huà) …… 《50 誡 》(注:指《Effective C++ 2/e》一書(shū))中提到過(guò),如果你的類(lèi)里面有指針指向動(dòng)態(tài)分配的內(nèi)存,那么一定要為它寫(xiě)一個(gè)拷貝構(gòu)造函數(shù)和一個(gè)賦值運(yùn)算符 …… 因?yàn)?…… 否則的話(huà),一旦你做了賦值,會(huì)導(dǎo)致兩個(gè)對(duì)象的指針指向同一塊內(nèi)存。對(duì)了!如果是上面的類(lèi),這樣一來(lái)會(huì)導(dǎo)致同一個(gè)指針被 delete 兩次!”

            “正確。那么我們應(yīng)該怎樣來(lái)實(shí)現(xiàn)呢?”

            “這簡(jiǎn)單,我們用 memcpy 把目標(biāo)指針指向的內(nèi)存中的內(nèi)容拷貝過(guò)來(lái)。”

            “如果我們的智能指針指向一個(gè)類(lèi)的對(duì)象怎么辦?注意,類(lèi)的對(duì)象中可能有指針,不能用 memcpy。”

            “那 …… 我們用拷貝構(gòu)造的辦法。”

            “如果我們的智能指針指向的對(duì)象不能拷貝構(gòu)造怎么辦?它可能有一個(gè)私有的拷貝構(gòu)造函數(shù)。”

            “那 ……”,zero 頓了一頓,決定老實(shí)承認(rèn),“我不知道。”

            “問(wèn)題在哪你知道么?在于你沒(méi)有把智能指針看作指針。想象一下,如果我們對(duì)一個(gè)指針做賦值,它的含義是什么?”

            “呃,我明白了,在這種情況下,應(yīng)該想辦法讓兩個(gè)智能指針指向同一個(gè)對(duì)象 …… 可是 Solmyr ,這樣以來(lái)豈不是仍然要對(duì)同一個(gè)對(duì)象刪除兩遍?”

            “是的,我們得想辦法解決這 個(gè)問(wèn)題,辦法不只一種。比較好的一種是為每個(gè)指針維護(hù)一個(gè)引用計(jì)數(shù)值,每次賦值或者拷貝構(gòu)造,就讓計(jì)數(shù)值加一,這意味著指向這個(gè)內(nèi)存塊的智能指針又多了一 個(gè);而每有一個(gè)智能指針被銷(xiāo)毀,就讓計(jì)數(shù)值減一,這意味著指向這個(gè)內(nèi)存塊的智能指針少了一個(gè);一旦計(jì)數(shù)值為 0 ,就釋放內(nèi)存塊。象這樣:”

            class my_intptr
            {
            private:
            int* m_p;
            int* m_count;

            public:
            my_intptr(int* p)
            {
            m_p = p;
            m_count = new int; // 初始化計(jì)數(shù)值為 1
            *m_count = 1;
            }
            my_intptr(const my_intptr& rhs) // 拷貝構(gòu)造函數(shù)
            {
            m_p = rhs.m_p; // 指向同一塊內(nèi)存
            m_count = rhs.m_count; // 使用同一個(gè)計(jì)數(shù)值
            (*m_count)++; // 計(jì)數(shù)值加 1
            }
            ~my_intptr()
            {
            (*m_count)--; // 計(jì)數(shù)值減 1
            if( *m_count == 0 ) // 已經(jīng)沒(méi)有別的指針指向該內(nèi)存塊了
            {
            delete m_p;
            delete m_count;
            }
            }

            my_intptr& operator=(const my_intptr& rhs)
            {
            if( m_p == rhs.m_p ) // 首先判斷是否本來(lái)就指向同一內(nèi)存塊
            return *this; // 是則直接返回

            (*m_count)--; // 計(jì)數(shù)值減 1 ,因?yàn)樵撝羔槻辉僦赶蛟瓉?lái)內(nèi)存塊了
            if( *m_count == 0 ) // 已經(jīng)沒(méi)有別的指針指向原來(lái)內(nèi)存塊了
            {
            delete m_p;
            delete m_count;
            }

            m_p = rhs.m_p; // 指向同一塊內(nèi)存
            m_count = rhs.m_count; // 使用同一個(gè)計(jì)數(shù)值
            (*m_count)++; // 計(jì)數(shù)值加 1
            }

            …………
            };

            “其他部分沒(méi)有什么太大變化,我不費(fèi)事了。現(xiàn)在想象一下我們?cè)鯓邮褂眠@種智能指針?”,Solmyr 放下了筆,再次拿起了筷子,有些惋惜的發(fā)現(xiàn)他愛(ài)吃的肉丸子已經(jīng)冷了。

            zero 想象著,有些遲疑。“我們 …… 可以用 new int 表達(dá)式作為構(gòu)造函數(shù)的參數(shù)來(lái)構(gòu)造一個(gè)智能指針,然后 …… 然后我們可以任意的賦值,”,他開(kāi)始抓住了思路,越說(shuō)越快,“任意的用已經(jīng)存在的智能指針來(lái)構(gòu)造新的智能指針,智能指針的賦值運(yùn)算符、拷貝構(gòu)造函數(shù)和析構(gòu) 會(huì)保證計(jì)數(shù)值始終等于指向該內(nèi)存塊的智能指針數(shù)。”zero 似乎明白了他看到了怎樣的功能, 開(kāi)始激動(dòng)起來(lái):“然后一旦計(jì)數(shù)值為 0 被分配的內(nèi)存塊就會(huì)釋放!也就是說(shuō) …… 有指針指向內(nèi)存塊,它就不釋放,一旦沒(méi)有,它就自動(dòng)釋放!太棒了!我們只要一開(kāi)始正確的初始化智能指針,就可以象普通指針那樣使用它,而且完全不用擔(dān)心內(nèi) 存釋放的問(wèn)題!太棒了!”zero 激動(dòng)的大叫:“這就是垃圾收集!Solmyr !我們?cè)陲堊郎蠈?shí)現(xiàn)了一個(gè)垃圾收集器!”

            Solmyr 很明顯沒(méi)有分享 zero 的激動(dòng):“我在吃飯,你能不能不要大叫‘飯桌上實(shí)現(xiàn)了一個(gè)垃圾收集器’這種倒胃口的話(huà)?”頓了一頓,Solmyr 帶著他招牌式的壞笑,以一種可惡的口吻說(shuō)道:“而且請(qǐng)注意一下自己的形象。”

            “嗯?”,zero 回過(guò)神來(lái),發(fā)現(xiàn)自己不知什么時(shí)候站了起來(lái),而整個(gè)餐廳里的人都在看著他嘿嘿偷笑,這讓他感覺(jué)自己像個(gè)傻瓜。

            zero 紅著臉坐下,壓低了聲音問(wèn) Solmyr :“不過(guò) Solmyr ,這確實(shí)是一個(gè)的垃圾收集機(jī)制啊,只要我們把這個(gè)類(lèi)改成 …… 嗯 …… 改成模板類(lèi),象這樣:”zero 抓過(guò)了紙筆,寫(xiě)到:

            template <typename T>
            class my_ptr
            {
            private:
            T* m_p;
            int* m_count;
            …………
            };

            “它不就能支持任意類(lèi)型的指針了嗎?我們就可以把它用在任何地方。”

            Solmyr 搖了搖頭:“不,你把問(wèn)題想的太簡(jiǎn)單了。對(duì)于簡(jiǎn)單的類(lèi)型,這個(gè)類(lèi)確實(shí)可以處理的很好,但實(shí)際情況是很復(fù)雜的。考慮一個(gè)典型情況:類(lèi) Derived 是類(lèi) Base 的派生類(lèi),我們希望這樣賦值:”

            Base* pb;
            Derived pd;
            …………
            pb = pd;

            “你倒說(shuō)說(shuō)看,這種情況,怎樣改用上面這個(gè)智能指針來(lái)處理?”

            “……”,zero 沉默了。

            “要實(shí)現(xiàn)一個(gè)完整的垃圾收集機(jī)制并不容易,因?yàn)橛性S多細(xì)節(jié)要考慮。”,Solmyr 開(kāi)始總結(jié)了,“不過(guò),基本思路就是上面說(shuō)的這些。值得慶幸的是,目前已經(jīng)有了一個(gè)相當(dāng)成熟的‘引用計(jì)數(shù)’智能指針,boost::shared_ptr。 大多數(shù)情況下,我們都可以使用它。另外,除了智能指針之外,還有一些技術(shù)也能夠幫助我們避開(kāi)釋放內(nèi)存的問(wèn)題,比如內(nèi)存池。但是,關(guān)鍵在于 ——— ”

            Solmyr 再度用那種平靜的眼神盯著 zero :

            “身為 C/C++ 程序員,必須有創(chuàng)造力。那種躺在語(yǔ)言機(jī)制上不思進(jìn)取的人,那種必須要靠語(yǔ)法強(qiáng)制才知道怎樣編程的人,那種沒(méi)有別人告訴他該干什么就無(wú)所適從的人,不適合這門(mén)語(yǔ)言。
            posted on 2010-04-13 17:36 楚天清秋 閱讀(280) 評(píng)論(0)  編輯 收藏 引用 所屬分類(lèi): C,C++
            人妻久久久一区二区三区| 久久久久久久波多野结衣高潮| 人妻中文久久久久| 精品久久久久久无码人妻蜜桃| 久久99精品国产自在现线小黄鸭| 国产精品久久久久a影院| 亚洲精品97久久中文字幕无码| 久久国产一片免费观看| 久久人人超碰精品CAOPOREN | 久久青青国产| 久久国产成人午夜aⅴ影院| 亚洲国产精品婷婷久久| 99久久精品这里只有精品 | 国产视频久久| 精品久久久久久无码免费| 欧美精品福利视频一区二区三区久久久精品 | 久久精品人人槡人妻人人玩AV | 久久久久婷婷| 2021最新久久久视精品爱| 精品国产乱码久久久久软件| 色欲久久久天天天综合网| 久久成人国产精品二三区| 99久久久久| 中文精品久久久久人妻不卡| 国产精品美女久久久| 久久久久国产一区二区| 99精品国产综合久久久久五月天| 老色鬼久久亚洲AV综合| 亚洲国产精品久久久久婷婷软件| 狠狠色丁香婷婷综合久久来来去 | 久久综合伊人77777| 久久精品国产亚洲AV蜜臀色欲 | 囯产极品美女高潮无套久久久 | 99久久99久久精品免费看蜜桃| 日本三级久久网| 亚洲中文字幕无码久久2020| 久久香蕉国产线看观看99| 久久99精品国产麻豆宅宅| 狠狠色综合网站久久久久久久| 久久亚洲精品无码AV红樱桃| 欧美性猛交xxxx免费看久久久|