<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                我們的“三板斧”,其實就是三個例子。相信這三板斧劈下去,你會很容易理解它們。 **例子1** ~~~ /類A從RefBase派生,RefBase是萬物的始祖 class A:public RefBase { //A沒有任何自己的功能 } int main() { A* pA =new A; { //注意我們的sp,wp對象是在{}中創建的,下面的代碼先創建sp,然后創建wp sp<A>spA(A); wp<A>wpA(spA); //大括號結束前,先析構wp,再析構sp } } ~~~ 例子夠簡單吧?但也需一步一步分析這斧子是怎么劈下去的。 1. RefBase和它的影子 類A從RefBase中派生。使用的是RefBase構造函數。代碼如下所示: **RefBase.cpp** ~~~ RefBase::RefBase() :mRefs(new weakref_impl(this))//注意這句話 { //mRefs是RefBase的成員變量,類型是weakref_impl,我們暫且叫它影子對象 //所以A有一個影子對象 } ~~~ mRefs是引用計數管理的關鍵類,需要進去觀察。它是從RefBase的內部類weakref_type中派生出來的。 先看看它的聲明: ~~~ class RefBase::weakref_impl : public RefBase::weakref_type //從RefBase的內部類weakref_type派生 ~~~ 由于Android頻繁使用C++內部類的方法,所以初次閱讀Android代碼時可能會有點不太習慣,C++的內部類和Java內部類相似,但不同的是,它需要一個顯示的成員指向外部類對象,而Java內部類對象就有一個隱式的成員指向外部類對象。 說明:內部類在C++中的學名叫nested class(內嵌類)。 **RefBase.cpp::weakref_imple構造** ~~~ weakref_impl(RefBase* base) :mStrong(INITIAL_STRONG_VALUE) //強引用計數,初始值為0x1000000 ,mWeak(0) //弱引用計數,初始值為0 ,mBase(base)//該影子對象所指向的實際對象 ,mFlags(0) ,mStrongRefs(NULL) ,mWeakRefs(NULL) ,mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT) ,mRetain(false) { } ~~~ 如你所見,new了一個A對象后,其實還new了一個weakref_impl對象,這里稱它為影子對象,另外我們稱A為實際對象。 這里有一個問題:影子對象有什么用? 可以仔細想一下,是不是發現影子對象成員中有兩個引用計數?一個強引用,一個弱引用。如果知道引用計數和對象生死有些許關聯的話,就容易想到影子對象的作用了。 按上面的分析,在構造一個實際對象的同時,還會悄悄地構造一個影子對象,在嵌入式設備的內存不是很緊俏的今天,這個影子對象的內存占用已不成問題了。 2. sp上場 程序繼續運行,現在到了 ~~~ sp<A> spA(A); ~~~ 請看sp的構造函數,它的代碼如下所示:(注意,sp是一個模板類,對此不熟悉的讀者可以去翻翻書,或者干脆把所有出現的T都換成A。) **RefBase.h::sp(T*other)** ~~~ template<typename T> sp<T>::sp(T* other) //這里的other就是剛才創建的pA :m_ptr(other)// sp保存了pA的指針 { if(other) other->incStrong(this);//調用pA的incStrong } ~~~ OK,戰場轉到RefBase的incStrong中。它的代碼如下所示: **RefBase.cpp** ~~~ void RefBase::incStrong(const void* id) const { //mRefs就是剛才RefBase構造函數中new出來的影子對象 weakref_impl*const refs = mRefs; //操作影子對象,先增加弱引用計數 refs->addWeakRef(id); refs->incWeak(id); ...... ~~~ 先來看看影子對象的這兩個weak函數都干了些什么。 (1)眼見而心不煩 先來看第一個函數addWeakRef,代碼如下所示: **RefBase.cpp** ~~~ void addWeakRef(const void* /*id*/) { } ~~~ 呵呵,addWeakRef啥都沒做,因為這是release版走的分支。調試版的代碼我們就不討論了,它是給創造RefBase、 sp,以及wp的人調試用的。 調試版分支的代碼很多,看來創造它們的人,也為不理解它們之間的曖昧關系痛苦不已。 總之,一共有這么幾個不用考慮的函數,我們都已列出來了。以后再碰見它們,干脆就直接跳過的是: ~~~ void addStrongRef(const void* /*id*/) { } void removeStrongRef(const void* /*id*/) { } void addWeakRef(const void* /*id*/) { } void removeWeakRef(const void* /*id*/) { } void printRefs() const { } void trackMe(bool, bool) { } ~~~ 繼續我們的征程。再看incWeak函數,代碼如下所示: **RefBase.cpp** ~~~ void RefBase::weakref_type::incWeak(const void*id) { weakref_impl* const impl = static_cast<weakref_impl*>(this); impl->addWeakRef(id); //上面說了,非調試版什么都不干 const int32_tc = android_atomic_inc(&impl->mWeak); //原子操作,影子對象的弱引用計數加1 //千萬記住影子對象的強弱引用計數的值,這是徹底理解sp和wp的關鍵 } ~~~ 好,我們再回到incStrong,繼續看代碼: **RefBase.cpp** ~~~ ...... //剛才增加了弱引用計數 //再增加強引用計數 refs->addStrongRef(id);//非調試版這里什么都不干 //下面函數為原子加1操作,并返回舊值。所以c=0x1000000,而mStrong變為0x1000001 const int32_t c =android_atomic_inc(&refs->mStrong); if (c!= INITIAL_STRONG_VALUE) { //如果c不是初始值,則表明這個對象已經被強引用過一次了 return; } //下面這個是原子加操作,相當于執行refs->mStrong +(-0x1000000),最終mStrong=1 android_atomic_add(-INITIAL_STRONG_VALUE,&refs->mStrong); /* 如果是第一次引用,則調用onFirstRef,這個函數很重要,派生類可以重載這個函數,完成一些 初始化工作。 */ const_cast<RefBase*>(this)->onFirstRef(); } ~~~ 說明:android_atomic_xxx是Android平臺提供的原子操作函數,原子操作函數是多線程編程中的常見函數,讀者可以學習原子操作函數知識,本章后面將對其做介紹。 (2)sp構造的影響 sp構造完后,它給這個世界帶來了什么? - 那就是RefBase中影子對象的強引用計數變為1,弱引用計數也變為1。 更準確的說法是,sp的出生導致影子對象的強引用計數加1,弱引用計數加1。 (3)wp構造的影響 繼續看wp,例子中的調用方式如下: ~~~ wp<A> wpA(spA) ~~~ wp有好幾個構造函數,原理都一樣。來看這個最常見的: **RefBase.h::wp(constsp<T>& other)** ~~~ template<typename T> wp<T>::wp(const sp<T>& other) :m_ptr(other.m_ptr) //wp的成員變量m_ptr指向實際對象 { if(m_ptr) { //調用pA的createWeak,并且保存返回值到成員變量m_refs中 m_refs = m_ptr->createWeak(this); } } ~~~ **RefBase.cpp** ~~~ RefBase::weakref_type* RefBase::createWeak(constvoid* id) const { //調用影子對象的incWeak,這個我們剛才講過了,將導致影子對象的弱引用計數增加1 mRefs->incWeak(id); returnmRefs; //返回影子對象本身 } ~~~ 我們可以看到,wp化后,影子對象的弱引用計數將增加1,所以現在弱引用計數為2,而強引用計數仍為1。另外,wp中有兩個成員變量,一個保存實際對象,另一個保存影子對象。sp只有一個成員變量用來保存實際對象,但這個實際對象內部已包含了對應的影子對象。 OK,wp創建完了,現在開始進入wp的析構。 (4)wp析構的影響 wp進入析構函數,這表明它快要離世了。 **RefBase.h** ~~~ template<typename T> wp<T>::~wp() { if(m_ptr) m_refs->decWeak(this); //調用影子對象的decWeak,由影子對象的基類實現 } ~~~ **RefBase.cpp** ~~~ void RefBase::weakref_type::decWeak(const void*id) { //把基類指針轉換成子類(影子對象)的類型,這種做法有些違背面向對象編程的思想 weakref_impl*const impl = static_cast<weakref_impl*>(this); impl->removeWeakRef(id);//非調試版不做任何事情 //原子減1,返回舊值,c=2,而弱引用計數從2變為1 constint32_t c = android_atomic_dec(&impl->mWeak); if (c !=1) return; //c=2,直接返回 //如果c為1,則弱引用計數為0,這說明沒用弱引用指向實際對象,需要考慮是否釋放內存 // OBJECT_LIFETIME_XXX和生命周期有關系,我們后面再說。 if((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) { if(impl->mStrong == INITIAL_STRONG_VALUE) delete impl->mBase; else { delete impl; } } else{ impl->mBase->onLastWeakRef(id); if((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) { delete impl->mBase; } } } ~~~ OK,在例1中,wp析構后,弱引用計數減1。但由于此時強引用計數和弱引用計數仍為1,所以沒有對象被干掉,即沒有釋放實際對象和影子對象占據的內存。 (5)sp析構的影響 下面進入sp的析構。 **RefBase.h** ~~~ template<typename T> sp<T>::~sp() { if(m_ptr) m_ptr->decStrong(this); //調用實際對象的decStrong。由RefBase實現 } ~~~ **RefBase.cpp** ~~~ void RefBase::decStrong(const void* id) const { weakref_impl* const refs = mRefs; refs->removeStrongRef(id);//調用影子對象的removeStrongRef,啥都不干 //注意,此時強弱引用計數都是1,下面函數調用的結果是c=1,強引用計數為0 constint32_t c = android_atomic_dec(&refs->mStrong); if (c== 1) { //對于我們的例子, c為1 //調用onLastStrongRef,表明強引用計數減為0,對象有可能被delete const_cast<RefBase*>(this)->onLastStrongRef(id); //mFlags為0,所以會通過delete this把自己干掉 //注意,此時弱引用計數仍為1 if((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) { delete this; } ...... } ~~~ 先看delete this的處理,它會導致A的析構函數被調用;再看A的析構函數,代碼如下所示: **例子1::~A()** ~~~ //A的析構直接導致進入RefBase的析構。 RefBase::~RefBase() { if(mRefs->mWeak == 0) { //弱引用計數不為0,而是1 delete mRefs; } } ~~~ RefBase的delete this自殺行為沒有把影子對象干掉,但我們還在decStrong中,可接著從delete this往下看: **RefBase.cpp** ~~~ ....//接前面的delete this if ((refs->mFlags&OBJECT_LIFETIME_WEAK)!= OBJECT_LIFETIME_WEAK) { delete this; } //注意,實際數據對象已經被干掉了,所以mRefs也沒有用了,但是decStrong剛進來 //的時候就保存mRefs到refs了,所以這里的refs指向影子對象 refs->removeWeakRef(id); refs->decWeak(id);//調用影子對象decWeak } ~~~ **RefBase.cpp** ~~~ void RefBase::weakref_type::decWeak(const void*id) { weakref_impl*const impl = static_cast<weakref_impl*>(this); impl->removeWeakRef(id);//非調試版不做任何事情 //調用前影子對象的弱引用計數為1,強引用計數為0,調用結束后c=1,弱引用計數為0 constint32_t c = android_atomic_dec(&impl->mWeak); if (c!= 1) return; //這次弱引用計數終于變為0,并且mFlags為0, mStrong也為0。 if((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) { if(impl->mStrong == INITIAL_STRONG_VALUE) delete impl->mBase; else { delete impl; //impl就是this,把影子對象自己干掉 } } else{ impl->mBase->onLastWeakRef(id); if((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) { delete impl->mBase; } } } ~~~ 好,第一板斧劈下去了!來看看它的結果是什么。 3. 第一板斧的結果 第一板斧過后,來總結一下剛才所學的知識: - RefBase中有一個隱含的影子對象,該影子對象內部有強弱引用計數。 - sp化后,強弱引用計數各增加1,sp析構后,強弱引用計數各減1。 - wp化后,弱引用計數增加1,wp析構后,弱引用計數減1。 完全徹底地消滅RefBase對象,包括讓實際對象和影子對象滅亡,這些都是由強弱引用計數控制的,另外還要考慮flag的取值情況。當flag為0時,可得出如下結論: - 強引用為0將導致實際對象被delete。 - 弱引用為0將導致影子對象被delete。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看