现在的位置: 首页 > 综合 > 正文

智能指针

2018年02月15日 ⁄ 综合 ⁄ 共 21717字 ⁄ 字号 评论关闭

引入智能指针的目的:


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;
}

抱歉!评论已关闭.