智能指針

引入智能指針的目的:

C++代碼中使用指針時常常忘記釋放,造成內存泄露等,甚至系統崩潰等。在Android中爲了解決這個問題,引入了C++智能指針

智能指針的原理:

Android中的智能指針以引用計數的實現的。引用計數是內存管理中比較常用的一種技術,其實現原理是:每當一個新的指針指向了一個對象時,這個對象的引用計數就加1;相反,每當一個指針不在指向一個對象時,這個對象的引用計數就減1;當對象的引用計數爲0時,則釋放對象。

瞭解了引用計數的基本原理以後,我們會發現這裏有兩個關鍵問題:
  1. 對象的引用計數應該有誰來維護?
  2. 如何解決對象循環引用的問題?
對於第一個問題:如果有開發人員來維護對象的引用計數,既不方便可靠,也容易出錯,不能從根本上解決“忘記釋放”的問題。最好能有一種自動的對象引用維護技術。這裏我們想到了構造函數與析構函數,在智能指針構造時增加他所引用的對象的引用計數,在智能指針析構時減少他所引用的對象的引用計數,剛好可以滿足要求。

在《Android源代碼 情景分析》中關於智能指針有這麼一段描述:智能指針是一種能夠自動維護對象引用計數的技術。這裏需要特別強調的是,智能指針是一個對象而不是一個指針,但是他引用了一個實際使用的對象。正是因爲他是一個對象,因此它能夠自動地維護實際對象的引用計數。簡單來說,就是在智能指針構造時,增加它所引用的對象的引用計數;在智能指針析構時,就減少他所引用的對象的引用計數。由於智能指針的構造函數和析構函數都是自動的,因此,它就很自然的實現了自動的對象引用計數計數。

對於第二個問題:Android中引入的強指針(sp)和弱指針(wp)的概念。

基本智能指針的實現:

智能指針是通過引用技術實現指針指向的對象的共享,對象的創建和刪除(主要是刪除)交給智能指針處理,而不用用戶過分關心。
實現智能指針需要兩步:一是爲指向的對象關聯引用計數,二是構造智能指針對象。

引用計數是目標對象的屬性,實現方法是:編寫基類,實現引用計數的維護,然後讓指向的類繼承該基類,獲得引用技術的屬性。該基類在Android系統中爲LightRefBase和RefBase,實現在frameworks\native\include\utils\RefBase.h中。

智能指針本身是一個對象,負責維護引用計數並根據引用計數delete引用對象。

智能指針的實現:

Android系統提供了三種類型的C++智能指針,分別爲輕量級指針(Light Pointer)、強指針(Strong Pointer)和弱指針(Weak Pointer),其中輕量級指針使用了簡單的引用計數技術,而強指針和弱指針使用了強引用和弱引用計數技術。無論是輕量級指針,還是強指針或弱指針,他們的實現原理都是類似的,
要達到所有對象都可用引用計數器實現智能指針管理的目標,Android系統將引用計數器定義爲一個公共類,提供引用計數的方法,所有支持使用智能指針的對象都去繼承這個公共類(子類的構造函數和析構函數會自動調用父類中的構造函數和析構函數),這樣就可以實現所有對象都可以用引用計數來管理的目標,在Android中,這個公共類就是RefBase,同時還有一個簡單版本LightRefBase。

這裏有一點需要注意的是,繼承了這個公共類(以ReferenceCounter表示)的類就不能再多繼承其他實類了,否則將無法正確釋放對象的空間。

classCDerivation : public CBase, public ReferenceCounter
{
   ...
};

如果其中CBase是一個實類,那麼,這樣的代碼是不允許的,Debug的時候,要釋放空間的地址並不是CDerivation對象的地址,而是ReferenceCounter對象地址相對於CDerivation對象的地址的偏移地址。爲了解決這個問題,可以令基類繼承自ReferenceCounter類,其他派生類繼承基類的同時也就繼承了ReferenceCounter類。例如,

classCBase : public ReferenceCounter
{
  ...
};
classCDerivation : public CBase
{
  ...
};

注意,上面所說的是不能多重繼承其他實類,如果一個類想使用引用計數指針,並且除了繼承ReferenceCounter類以外,繼承的其他類都是接口(就是隻包含純虛函數、靜態常量和靜態常量,且不包含任何其他成員變量或函數的類,這種接口的概念與Java和C#中接口的概念幾乎相同),那麼,這種多重繼承是允許的。例如,

#include <iostream>
 using namespace std;

#include "RefCountedPointer.h"
#include "ReferenceCounter.h"

 struct IInterfaceA
{
        static int IA;
        virtual void displayA(void)= 0;
        virtual void displayB(void)= 0;
};

 int IInterfaceA::IA = 100;

 struct IInterfaceB
{
        static int IB;
        virtual void displayC(void)= 0;
        virtual void displayD(void)= 0;
};

 int IInterfaceB::IB = 102;

 class CClass : publicReferenceCounter, public IInterfaceA, public IInterfaceB
{
public:
        int a;
        int b;
        int c;
        int d;
public:
        virtual void displayA(void)
        {
                cout<<a;
        }

        virtual void displayB(void)
        {
                cout<<b;
        }

        virtual void displayC(void)
        {
                cout<<c;
        }

        virtual void displayD(void)
        {
                cout<<d;
        }
};

void main(void)
{
        RefCountedPointer<CClass> p = new CClass;
        p->= 0;
        p->= 1;
        p->= 2;
        p->= 3;

        p->displayA();
        cout<<endl;
        p->displayB();
        cout<<endl;
        p->displayC();
        cout<<endl;
        p->displayD();
        cout<<endl;
}

輕量級引用計數的實現:LightRefBase

@frameworks/base/include/utils/RefBase.h
template <class T>
class LightRefBase
{
public:
    inline LightRefBase() : mCount(0) { }
    inline void incStrong(const void* id) const {
        android_atomic_inc(&mCount);
    }
    inline void decStrong(const void* id) const {
        if (android_atomic_dec(&mCount) == 1) {
            delete static_cast<const T*>(this);
        }
    }
    //! DEBUGGING ONLY: Get current strong ref count.
    inline int32_t getStrongCount() const {
        return mCount;
    }
    typedef LightRefBase<T> basetype;
protected:
    inline ~LightRefBase() { }
private:
    friend class ReferenceMover;
    inline static void moveReferences(void* d, void const* s, size_t n,
            const ReferenceConverterBase& caster) { }
private:
    mutable volatile int32_t mCount;
};

LightRefBase類通過mCount成員變量來描述一個對象的引用計數值。通過incStrong方法增加引用計數,decStrong方法減少引用計數。
LightRefBase類是一個模板類,其中模板參數T表示對象的實際類型,它必須是繼承了LightRefBase類的。

Android系統輕量級指針就是實現了基本的智能指針,比較容易理解。這種形式的智能指針很大程度上解決了C++指針問題,但如下場景還會力不從心:系統中有兩個對象A和B,在對象A的內部引用了對象B,而在對象B的內部也引用了對象A。當兩個對象A和B都不再使用時,系統會發現無法回收這兩個對象的所佔據的內存的,因爲系統一次只能回收一個對象,而無論系統決定要收回對象A還是要收回對象B時,都會發現這個對象被其它的對象所引用,因而就都回收不了,類似於死鎖現象,這樣就造成了內存泄漏。

針對這個問題,可以採用對象的引用計數同時存在強引用和弱引用兩種計數。例如A引用B則B的強引用計數和弱引用計數+1,而B引用A則A僅僅弱引用數+1,在回收時只要對象的強引用計數爲0,則不管弱引用數是否爲0都進行回收,類似於死鎖解決中的強制釋放資源,這樣問題得到解決。

Android中的強指針和弱指針

以下有幾個概念容易混淆,先提出來辨析

強指針支持指向兩種超類型的引用對象,一種是輕量級引用對象,繼承自LightRefBase,另一種姑且稱之爲重量級引用對象,繼承自RefBase。

弱指針只支持指向重量級引用對象,繼承自RefBase。

引用對象負責維護自己的引用計數,但引用計數器增加或減少的消息由sp或是wp智能指針對象發生。

LightRefBase和RefBase維護引用計數的方式不相同,前者直接使用int型變量維護,或者使用一個嵌套類weakref_type維護。

強引用計數和弱引用計數:目標對象關聯的兩個計數屬性,這兩個計數屬性同時存在,值由指針控制,不一定相等。

強指針和弱指針:是兩個不同的智能指針對象,在創建對象、拷貝構造以及析構的時候改變引用對象的強引用計數和弱引用計數,兩種指針的改變規則不同。

對象採用的引用計數方法:用flag表示目標對象在回收時受哪種強引用計數還是弱引用計數影響,4.0版本沒有了forever模式。

弱指針無法直接訪問對象,需要promote成強指針,但並不一定保證成功。


強指針的實現:sp(Strong Pointer)

 LightRefBase僅僅提供了引用計數的方法,具體引用數應該怎麼管理,就要通過智能指針類來管理了,每當有一個智能指針指向對象時,對象的引用計數要加1,當一個智能指針取消指向對象時,對象的引用計數要減1,在C++中,當一個對象生成和銷燬時會自動調用(拷貝)構造函數和析構函數,所以,對對象引用數的管理就可以放到智能指針的(拷貝)構造函數和析構函數中。Android提供了一個智能指針可以配合LightRefBase使用:sp,sp的定義如下:

@frameworks/base/includes/utils/StrongPointer.h
template <typename T>
class sp
{
public:
    inline sp() : m_ptr(0) { }
    sp(T* other);
    sp(const sp<T>& other);
    template<typename U> sp(U* other);
    template<typename U> sp(const sp<U>& other);
    ~sp();
    // Assignment
    sp& operator = (T* other);
    sp& operator = (const sp<T>& other);
    template<typename U> sp& operator = (const sp<U>& other);
    template<typename U> sp& operator = (U* other);
    //! Special optimization for use by ProcessState (and nobody else).
    void force_set(T* other);
    // Reset
    void clear();
    // Accessors
    inline  T&      operator* () const  { return *m_ptr; }
    inline  T*      operator-> () const { return m_ptr;  }
    inline  T*      get() const         { return m_ptr; }
    // Operators
    COMPARE(==)
    COMPARE(!=)
    COMPARE(>)
    COMPARE(<)
    COMPARE(<=)
    COMPARE(>=)
private:    
    template<typename Y> friend class sp;
    template<typename Y> friend class wp;
    void set_pointer(T* ptr);
    T* m_ptr;
};

代碼比較多,其中Accessors部分代碼重載了*、->操作符使我們使用sp的時候就像使用真實的對象指針一樣,可以直接操作對象的屬性或方法,COMPARE是宏定義,用於重載關係操作符,由於對引用計數的控制主要是由(拷貝)構造函數和析構函數控制,所以忽略其他相關代碼後,sp可以精簡爲如下形式(賦值操作符也省略掉了,構造函數省略相似的兩個):

template <typename T>
class sp
{
public:
    inline sp() : m_ptr(0) { }
    sp(T* other);
    sp(const sp<T>& other);
                                        
    ~sp();
                                        
private:  
    template<typename Y> friend class sp;
    template<typename Y> friend class wp;
    void set_pointer(T* ptr);
    T* m_ptr;
};

默認構造函數使智能指針不指向任何對象,另外還有一個普通的構造函數和拷貝構造函數:sp(T* other)與sp(const sp<T>& other)的實現如下:

template<typename T>
sp<T>::sp(T* other)
: m_ptr(other)
  {
    if (other) other->incStrong(this);
  }
template<typename T>
sp<T>::sp(const sp<T>& other)
: m_ptr(other.m_ptr)
  {
    if (m_ptr) m_ptr->incStrong(this);
  }

sp中成員變量m_ptr是一個指針,它在sp的構造函數裏面初始化的,指向實際引用的對象,並調用實際對象的incStrong函數,T繼承自LightRefBase,所以此處調用的是LightRefBase的incStrong函數,之後實際對象的引用計數加1。

當指針銷燬時調用sp的析構函數如下:

template<typename T>
sp<T>::~sp()
{
    if (m_ptr) m_ptr->decStrong(this);
}

RefBase

強指針和弱指針通過強引用計數和弱引用計數來維護對象的生命週期。如果一個類的對象要支持使用強指針和弱指針,那麼它就必須從RefBase類繼承下來,因爲RefBase提供了強引用計數器和弱引用計數器。

RefBase提供了incStrong與decStrong函數用於控制強引用計數值,其弱引用計數值是由weakref_impl控制,強引用計數與弱引用數都保存在weakref_impl *類型的成員變量mRefs中。

RefBase同LightRefBase一樣爲對象提供了引用計數的方法,對引用計數的管理同樣要由智能指針控制,由於RefBase同時實現了強引用計數與弱引用計數,所以就有兩種類型的智能指針,sp(Strong Pointer)與wp(Weak Pointer)。

@frameworks/base/include/utils/RefBase.h
class RefBase
{
public:
            void            incStrong(const void* id) const;
            void            decStrong(const void* id) const;
    
            void            forceIncStrong(const void* id) const;
            //! DEBUGGING ONLY: Get current strong ref count.
            int32_t         getStrongCount() const;
    class weakref_type
    {
    public:
        RefBase*            refBase() const;
        
        void                incWeak(const void* id);
        void                decWeak(const void* id);
        
        // acquires a strong reference if there is already one.
        bool                attemptIncStrong(const void* id);
        
        // acquires a weak reference if there is already one.
        // This is not always safe. see ProcessState.cpp and BpBinder.cpp
        // for proper use.
        bool                attemptIncWeak(const void* id);
        //! DEBUGGING ONLY: Get current weak ref count.
        int32_t             getWeakCount() const;
        //! DEBUGGING ONLY: Print references held on object.
        void                printRefs() const;
        //! DEBUGGING ONLY: Enable tracking for this object.
        // enable -- enable/disable tracking
        // retain -- when tracking is enable, if true, then we save a stack trace
        //           for each reference and dereference; when retain == false, we
        //           match up references and dereferences and keep only the 
        //           outstanding ones.
        
        void                trackMe(bool enable, bool retain);
    };
    
            weakref_type*   createWeak(const void* id) const;
            
            weakref_type*   getWeakRefs() const;
            //! DEBUGGING ONLY: Print references held on object.
    inline  void            printRefs() const { getWeakRefs()->printRefs(); }
            //! DEBUGGING ONLY: Enable tracking of object.
    inline  void            trackMe(bool enable, bool retain)
    { 
        getWeakRefs()->trackMe(enable, retain); 
    }
    typedef RefBase basetype;
protected:
                            RefBase();
    virtual                 ~RefBase();
    //! Flags for extendObjectLifetime()
    enum {
        OBJECT_LIFETIME_STRONG  = 0x0000,
        OBJECT_LIFETIME_WEAK    = 0x0001,
        OBJECT_LIFETIME_MASK    = 0x0001
    };
    
            void            extendObjectLifetime(int32_t mode);
            
    //! Flags for onIncStrongAttempted()
    enum {
        FIRST_INC_STRONG = 0x0001
    };
    
    virtual void            onFirstRef();
    virtual void            onLastStrongRef(const void* id);
    virtual bool            onIncStrongAttempted(uint32_t flags, const void* id);
    virtual void            onLastWeakRef(const void* id);
private:
    friend class ReferenceMover;
    static void moveReferences(void* d, void const* s, size_t n,
            const ReferenceConverterBase& caster);
private:
    friend class weakref_type;
    class weakref_impl;
    
                            RefBase(const RefBase& o);
            RefBase&        operator=(const RefBase& o);
        weakref_impl* const mRefs;
};

不同於LightRefBase的是,RefBase內部並沒有使用一個整數來維護引用計數,而是通過一個weakref_impl *類型的對象來維護引用計數(即成員變量mRefs來描述對象的引用計數),並且同時提供了強引用計數和弱引用計數。weakref_impl繼承於RefBase::weakref_type,代碼比較多,不過大都是調試代碼,由宏定義分開,Release是不包含調試代碼的,去除這些代碼後其定義爲:

@frameworks/base/include/utils/RefBase.cpp
class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
    volatile int32_t    mStrong;
    volatile int32_t    mWeak;
    RefBase* const      mBase;
    volatile int32_t    mFlags;

#if !DEBUG_REFS

    weakref_impl(RefBase* base)
        : mStrong(INITIAL_STRONG_VALUE)
        , mWeak(0)
        , mBase(base)
        , mFlags(0)
    {
    }

    void addStrongRef(const void* /*id*/) { }
    void removeStrongRef(const void* /*id*/) { }
    void renameStrongRefId(const void* /*old_id*/const void* /*new_id*/) { }
    void addWeakRef(const void* /*id*/) { }
    void removeWeakRef(const void* /*id*/) { }
    void renameWeakRefId(const void* /*old_id*/const void* /*new_id*/) { }
    void printRefs() const { }
    void trackMe(boolbool) { }

#else
    ......
#endif
};

 weakref_impl中的函數都是作爲調試用,Release版的實現都是空的,成員變量分別表示強引用數(mStrong)、弱引用數(mWeak)、指向實際對象的指針(mBase)與mFlags標識對象受哪種計數方式影響)。flag可控制實際對象的生命週期,取值爲RefBase中定義的枚舉值,其中OBJECT_LIFETIME_STRONG表示對象的生命週期只受強引用計數影響;OBJECT_LIFETIME_WEAK表示對象的生命週期同時受強引用計數和弱引用計數影響OBJECT_LIFETIME_MASK:表示對象的生命週期完全不受強引用計數或者弱引用計數的影響,迴歸到C++本身。

weakref_impl類中INITIAL_STRONG_VALUE的定義爲:

#define INITIAL_STRONG_VALUE (1<<28)

下面是RefBase類的構造函數:

RefBase::RefBase()
    : mRefs(new weakref_impl(this))
{
}

RefBase中通過mRefs維持對weakref_impl的引用,weakref_impl中通過mBase指向對象的實際類型,即RefBase。

在定義一個sp指向一個支持智能指針的對象時,調用RefBase 的incStrong。

template<typename T>
sp<T>::sp(T* other)
: m_ptr(other)
  {
    if (other) other->incStrong(this);
  }
template<typename T>
sp<T>::sp(const sp<T>& other)
: m_ptr(other.m_ptr)
  {
    if (m_ptr) m_ptr->incStrong(this);
  }

void RefBase::incStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->incWeak(id);
    
    refs->addStrongRef(id);
    const int32_t c = android_atomic_inc(&refs->mStrong);
    LOG_ASSERT(c > 0"incStrong() called on %p after last strong ref", refs);
#if PRINT_REFS
    LOGD("incStrong of %p from %p: cnt=%d\n"this, id, c);
#endif
    if (c != INITIAL_STRONG_VALUE)  {
        return;
    }
    android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
    refs->mBase->onFirstRef();
}

 addStrong的函數體爲空,incStrong函數內部首先調用成員變量mRefs的incWeak函數將弱引用數加1,然後再將強引用數加1,由於android_atomic_inc返回變量的舊值,所以如果其不等於INITIAL_STRONG_VALUE就直接返回,則則是第一次由強智能指針(sp)引用,將其減去INITIAL_STRONG_VALUE後變成1,然後調用對象的onFirstRef。

注意incStrong中的android_atomic_inc和android_atomic_add的參數,它們都是refs對象中的值,這也說明RefBase的引用計數是靠weakref_impl來維護的。

void RefBase::weakref_type::incWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->addWeakRef(id);
    const int32_t c = android_atomic_inc(&impl->mWeak);
    LOG_ASSERT(c >= 0"incWeak called on %p after last weak ref"this);
}

addWeakRef實現同樣爲空,所以只是將弱引用計數加1。所以當對象被sp引用後,強引用計數與弱引用計數會同時加1。

當sp銷燬時其析構函數調用對象即RefBase的decStrong函數:

template<typename T>
sp<T>::~sp()
{
    if (m_ptr) m_ptr->decStrong(this);
}

void RefBase::decStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->removeStrongRef(id);
    const int32_t c = android_atomic_dec(&refs->mStrong);
#if PRINT_REFS
    LOGD("decStrong of %p from %p: cnt=%d\n"this, id, c);
#endif
    LOG_ASSERT(c >= 1"decStrong() called on %p too many times", refs);
    if (c == 1) {
        refs->mBase->onLastStrongRef(id);
        if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
            delete this;
        }
    }
    refs->decWeak(id);
}

decStrong中將強引用數與弱引用數同時減1,如果這是最後一個強引用的話,會調用對象的onLastStrongRef,並且判斷成員變量mRefs的成員變量mFlags來決定是否在對象的強引用數爲0時釋放對象。

void RefBase::weakref_type::decWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->removeWeakRef(id);
    const int32_t c = android_atomic_dec(&impl->mWeak);
    LOG_ASSERT(c >= 1"decWeak called on %p too many times"this);
    if (c != 1return;
    if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
        // This is the regular lifetime case. The object is destroyed
        // when the last strong reference goes away. Since weakref_impl
        // outlive the object, it is not destroyed in the dtor, and
        // we'll have to do it here.
        if (impl->mStrong == INITIAL_STRONG_VALUE) {
            // Special case: we never had a strong reference, so we need to
            // destroy the object now.
            delete impl->mBase;
        } else {
            // LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
            delete impl;
        }
    } else {
        // less common case: lifetime is OBJECT_LIFETIME_{WEAK|FOREVER}
        impl->mBase->onLastWeakRef(id);
        if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
            // this is the OBJECT_LIFETIME_WEAK case. The last weak-reference
            // is gone, we can destroy the object.
            delete impl->mBase;
        }
    }
}

弱指針的實現:wp(Weak Pointer)

如果一個的對象支持使用弱指針,那麼這個類就必須要從RefBase類繼承下來,因爲RefBase累提供了弱引用計數器。wp類的定義如下:

@frameworks/base/include/utils/RefBase.h
template <typename T>
class wp
{
public:
    typedef typename RefBase::weakref_type weakref_type;
    
    inline wp() : m_ptr(0) { }
    wp(T* other);
    wp(const wp<T>& other);
    wp(const sp<T>& other);
    template<typename U> wp(U* other);
    template<typename U> wp(const sp<U>& other);
    template<typename U> wp(const wp<U>& other);
    ~wp();
    
    // Assignment
    wp& operator = (T* other);
    wp& operator = (const wp<T>& other);
    wp& operator = (const sp<T>& other);
    
    template<typename U> wp& operator = (U* other);
    template<typename U> wp& operator = (const wp<U>& other);
    template<typename U> wp& operator = (const sp<U>& other);
    
    void set_object_and_refs(T* other, weakref_type* refs);
    // promotion to sp
    
    sp<T> promote() const;
    // Reset
    
    void clear();
    // Accessors
    
    inline  weakref_type* get_refs() const { return m_refs; }
    
    inline  T* unsafe_get() const { return m_ptr; }
    // Operators
    COMPARE_WEAK(==)
    COMPARE_WEAK(!=)
    COMPARE_WEAK(>)
    COMPARE_WEAK(<)
    COMPARE_WEAK(<=)
    COMPARE_WEAK(>=)
    inline bool operator == (const wp<T>& o) const {
        return (m_ptr == o.m_ptr) && (m_refs == o.m_refs);
    }
    template<typename U>
    inline bool operator == (const wp<U>& o) const {
        return m_ptr == o.m_ptr;
    }
    inline bool operator > (const wp<T>& o) const {
        return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
    }
    template<typename U>
    inline bool operator > (const wp<U>& o) const {
        return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
    }
    inline bool operator < (const wp<T>& o) const {
        return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
    }
    template<typename U>
    inline bool operator < (const wp<U>& o) const {
        return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
    }
                         inline bool operator != (const wp<T>& o) const { return m_refs != o.m_refs; }
    template<typename U> inline bool operator != (const wp<U>& o) const { return !operator == (o); }
                         inline bool operator <= (const wp<T>& o) const { return !operator > (o); }
    template<typename U> inline bool operator <= (const wp<U>& o) const { return !operator > (o); }
                         inline bool operator >= (const wp<T>& o) const { return !operator < (o); }
    template<typename U> inline bool operator >= (const wp<U>& o) const { return !operator < (o); }
private:
    template<typename Y> friend class sp;
    template<typename Y> friend class wp;
    T*              m_ptr;
    weakref_type*   m_refs;
};

與強指針類相比,它們都有一個成員變量m_ptr指向目標對象,但是弱指針還有一個額外的成員變量m_refs,它的類型是weakref_type指針。強指針直接調用incStrong和decStrong,會同時增加或減少強引用計數和弱引用計數。弱指針調用createWeak進而調用incWeak,或者調用decWeak,隻影響弱引用計數,不影響強引用計數。

wp的構造函數:
template<typename T>
wp<T>::wp(T* other)
    : m_ptr(other)
{
    if (other) m_refs = other->createWeak(this);
}
template<typename T>
wp<T>::wp(const wp<T>& other)
    : m_ptr(other.m_ptr), m_refs(other.m_refs)
{
    if (m_ptr) m_refs->incWeak(this);
}
template<typename T>
wp<T>::wp(const sp<T>& other)
    : m_ptr(other.m_ptr)
{
    if (m_ptr) {
        m_refs = m_ptr->createWeak(this);
    }
}

createWeak的實現爲:
RefBase::weakref_type* RefBase::createWeak(const void* id) const
{
    mRefs->incWeak(id);
    return mRefs;
}

incWeak的實現爲:
void RefBase::weakref_type::incWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->addWeakRef(id);
    const int32_t c = android_atomic_inc(&impl->mWeak);
    LOG_ASSERT(c >= 0"incWeak called on %p after last weak ref"this);
}

wp的析構函數:
template<typename T>
wp<T>::~wp()
{
    if (m_ptr) m_refs->decWeak(this);
}

可以看出,在初始化wp是會在他的構造函數中調用incWeak增加弱引用計數,在析構時會調用decWeak來減少對象的弱引用計數。

弱指針的最大特點是它不能直接操作目標對象,這是怎麼樣做到的呢?祕密就在於弱指針類沒有重載*和->操作符號,而強指針重載了這兩個操作符號。但是,如果我們要操作目標對象,應該怎麼辦呢,這就要把弱指針升級爲強指針了。


template<typename T>
sp<T> wp<T>::promote() const
{
    sp<T> result;
    if (m_ptr && m_refs->attemptIncStrong(&result)) {
        result.set_pointer(m_ptr);
    }
    return result;
}


bool RefBase::weakref_type::attemptIncStrong(const void* id)
{
    incWeak(id);
    
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    
    int32_t curCount = impl->mStrong;
    LOG_ASSERT(curCount >= 0"attemptIncStrong called on %p after underflow",
               this);
    while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
        if (android_atomic_cmpxchg(curCount, curCount+1&impl->mStrong) == 0) {
            break;
        }
        curCount = impl->mStrong;
    }
    
    if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
        bool allow;
        if (curCount == INITIAL_STRONG_VALUE) {
            // Attempting to acquire first strong reference...  this is allowed
            // if the object does NOT have a longer lifetime (meaning the
            // implementation doesn't need to see this), or if the implementation
            // allows it to happen.
            allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
                  || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
        } else {
            // Attempting to revive the object...  this is allowed
            // if the object DOES have a longer lifetime (so we can safely
            // call the object with only a weak ref) and the implementation
            // allows it to happen.
            allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK
                  && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
        }
        if (!allow) {
            decWeak(id);
            return false;
        }
        curCount = android_atomic_inc(&impl->mStrong);
        // If the strong reference count has already been incremented by
        // someone else, the implementor of onIncStrongAttempted() is holding
        // an unneeded reference.  So call onLastStrongRef() here to remove it.
        // (No, this is not pretty.)  Note that we MUST NOT do this if we
        // are in fact acquiring the first reference.
        if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {
            impl->mBase->onLastStrongRef(id);
        }
    }
    
    impl->addStrongRef(id);
#if PRINT_REFS
    LOGD("attemptIncStrong of %p from %p: cnt=%d\n"this, id, curCount);
#endif
    if (curCount == INITIAL_STRONG_VALUE) {
        android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);
        impl->mBase->onFirstRef();
    }
    
    return true;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章