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

            S.l.e!ep.¢%

            像打了激速一樣,以四倍的速度運轉(zhuǎn),開心的工作
            簡單、開放、平等的公司文化;尊重個性、自由與個人價值;
            posts - 1098, comments - 335, trackbacks - 0, articles - 1
              C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

            std::tr1::shared_ptr 使用的一點體會

            Posted on 2010-09-03 22:29 S.l.e!ep.¢% 閱讀(4070) 評論(0)  編輯 收藏 引用 所屬分類: C++

            在 c++ 98 里面只有一種智能指針,就是 std::auto_ptr,因為具有唯一所有權(quán)的特征,所以限制了它的使用范圍,比如你無法在容器中使用它。而我們知道 stl 容器是值語義的,如果不能用智能指針管理的話,只有兩種辦法來使用。

            一種是類似這樣:

            std::vector<std::string> names;
            names.push_back("cyberscorpio");
            std::string name("news818");
            names.push_back(name);

            每次向容器中添加內(nèi)容的時候,實際上產(chǎn)生了該內(nèi)容的另一份拷貝,對于簡單的內(nèi)容(或?qū)ο螅﹣碚f,問題不大,但如果是很復(fù)雜的內(nèi)容,很大的對象,調(diào)用拷貝構(gòu)造函數(shù)的成本會比較高,同時亦不利于統(tǒng)一維護。

            另一種做法就是在容器中存指針,這樣當然就避免了上面的問題,但是,這需要你在容器對象銷毀的時候,顯式的釋放容器中的每一個元素。略有些不方便,但還可以接受。

            更大的問題在于,當程序比較復(fù)雜的時候,對象的生命周期管理對程序員來說,會是一個比較頭疼的事情,比如你有一個指針(對象),在程序的很多地方都用到它,如果你在某個地方釋放了它而沒有通知它的其他使用者的話,就會造成非法的內(nèi)存訪問,從而程序崩潰。

            shared_ptr 通過指針的引用計數(shù),很好的解決了這個問題,和 COM 組件生存期管理機制類似,只有當引用計數(shù)為 0 的時候,才會釋放這個對象。而 shared_ptr 不需要程序員手工調(diào)用 AddRef 和 Release 函數(shù),進一步減小了出錯的可能性。

            但是,引用計數(shù)有一個麻煩,它不能解決所謂循環(huán)引用的問題,舉個例子,有對象 A 和 B,A 和 B 中,各有一個智能指針指向?qū)Ψ健?/p>

            #include <stdio.h>
            #include <memory>
            class A;
            class B;
            typedef std::tr1::shared_ptr<a> APtr;
            typedef std::tr1::shared_ptr<b> BPtr;

            class A {
            public:
            BPtr b;
            ~A () {
            printf ("A released\n");
            }
            };

            class B {
            public:
            APtr a;
            ~B () {
            printf ("B released\n");
            }
            };

            int main () {
            APtr a(new A());
            BPtr b(new B());

            a->b = b; // 1
            b->a = a; // 2

            return 0;

            }

            我們編譯運行這段程序,會發(fā)現(xiàn) A 和 B 的析構(gòu)函數(shù)都沒有被調(diào)用,因為在只能指針 a 的生命周期結(jié)束的時候,它手中對 A 對象的引用計數(shù)還剩下 1 (即 b 手中的引用),所以對象 A 不會被釋放。而指針 b 生命結(jié)束的時候哦,它手中 B 對象的引用也還有 1,導(dǎo)致沒有對象被釋放。

            上面的例子里面,注釋為 1 和 2 的兩句,任意去掉一句,就打破了這個循環(huán)的引用,從而 A 和 B 都能正確的釋放。那么,假如我真的需要 A 和 B 之間互相引用,難道就沒有別的辦法了嗎?辦法是有的,就是使用 std::tr1::weak_ptr。weak_ptr,顧名思義,是一個 “弱” 一點的智能指針,它不會增加引用計數(shù),當你需要使用這個對象的時候,可以從 weak_ptr 臨時生出一個 shared_ptr 來 (通過 lock 函數(shù)),這個臨時的 shared_ptr 生命結(jié)束以后,就會把引用計數(shù)減小 1,這樣就不會出現(xiàn)互相死鎖的情況了。

            #include <stdio.h>
            #include <memory>
            class A;
            class B;

            typedef std::tr1::shared_ptr<A> APtr;
            typedef std::tr1::shared_ptr<B> BPtr;
            typedef std::tr1::weak_ptr<A> AWeakPtr;
            typedef std::tr1::weak_ptr<B> BWeakPtr;

            class A {
            public:
            BWeakPtr b; // 注意這里
            ~A () {
            printf ("A released\n");
            }

            };

            class B {
            public:
            AWeakPtr a; // 注意這里
            ~B () {
            printf ("B released\n");
            }

            void output () {
            printf ("I'm B\n");
            }
            };

            int main () {
            APtr a(new A());
            BPtr b(new B());

            a->b = b;
            b->a = a;

            BPtr b2(a->b.lock());
            b2->output();

            return 0;
            }

            編譯運行,我們會欣喜的看到,A 和 B 都正確的被釋放了。

            I'm B
            B released
            A released

            所以,在使用 shared_ptr 第一個要注意的,就是在可能會引起循環(huán)引用的地方,使用 weak_ptr

            還有一個問題也很常見,當使用了 shared_ptr 的時候,我們可能需要在所有的地方都使用它,否則就不容易達到管理生存期的目的了。但有的時候,我們手頭上只有對象的原始指針,比如在對象的函數(shù)內(nèi)部,我們只有 this。這就迫切的需要一個功能:如何從對象的裸指針中,生成我們需要的 shared_ptr。

            有人可能會覺得這個簡單,shared_ptr<T> a(this); 不就行了么?很遺憾的告訴你,這樣不行,會出問題。為什么呢?因為這里的 a,手中對 this 的引用計數(shù)只有 1,它無法知道其他地方智能指針對 this 這個指針(就是這個對象)的引用情況,因此當 a 的生命周期結(jié)束(比如函數(shù)返回)的時候,this 就會被它毫不留情的釋放掉,其他地方的相關(guān)智能指針,手中拿著的該對象指針已經(jīng)變成非法。

            那么怎樣解決呢?也很簡單,使用 std::tr1::enable_shared_from_this 作為基類。比如:

            class A : public std::tr1::enable_shared_from_this<A> 
            {
            public:
            std::tr1::shared_ptr<A> getSharedPtr() {
            return shared_from_this();
            }
            };

            這樣就可以從 this 中生出具有統(tǒng)一引用計數(shù)的 shared_ptr 了。只有一個問題是需要注意的,就是 getSharedPtr 函數(shù),或者說 shared_from_this 不能在對象 A 的構(gòu)造函數(shù)中調(diào)用。因為 enable_shared_from_this 這個基類的內(nèi)部,是通過一個對自己的 weak_ptr 的引用來返回 this 的 shared_ptr 的,而在對象的構(gòu)造函數(shù)中,第一個 shared_ptr 尚未獲得對象的指針,所以 weak_ptr 是空的,直接導(dǎo)致 shared_from_this() 返回失敗。除此以外,shared_from_this 可以隨便使用。

            中文字幕久久精品无码| 欧美日韩成人精品久久久免费看| 久久国产精品-国产精品| 亚洲愉拍99热成人精品热久久| 模特私拍国产精品久久| 久久中文字幕人妻丝袜| 97精品国产91久久久久久| 久久国产精品免费一区| 欧美熟妇另类久久久久久不卡| 久久久久女人精品毛片| 久久精品日日躁夜夜躁欧美| 国产精品免费久久| 一本色综合网久久| 久久天堂电影网| 久久人人爽爽爽人久久久| 久久久久四虎国产精品| 久久夜色精品国产| 国产国产成人久久精品| 精品久久久无码21p发布| 国产精品九九九久久九九| 亚洲欧美日韩久久精品| 国产高潮国产高潮久久久| 久久久精品人妻一区二区三区蜜桃| 人妻丰满AV无码久久不卡| 亚洲国产成人久久一区WWW| 久久国产精品无码一区二区三区| 亚洲伊人久久综合影院| 91性高湖久久久久| 一本色道久久88加勒比—综合| 久久久久久国产精品美女| 激情五月综合综合久久69| 久久久91精品国产一区二区三区| 伊人久久大香线蕉亚洲| 久久久久久曰本AV免费免费| 久久精品夜色噜噜亚洲A∨| 国产精品美女久久久免费| 狠色狠色狠狠色综合久久| 国产99精品久久| 狠狠干狠狠久久| 国产精品美女久久久| 国产精品久久久久久福利69堂|