android智能指针

下面是android 7.1.1中的源码
先从简单的LightRefBase开始, 它里面只用了简单的mCount来计数.

## LightRefBase

template <class T>
class LightRefBase
{
    public:
    inline LightRefBase() : mCount(0) { }
    //计数+1
    inline void incStrong(__attribute__((unused)) const void* id) const {
        mCount.fetch_add(1, std::memory_order_relaxed);
    }
    inline void decStrong(__attribute__((unused)) const void* id) const {
    //计数-1, 返回减1之前的值
       if (mCount.fetch_sub(1, std::memory_order_release) == 1) {
            std::atomic_thread_fence(std::memory_order_acquire);
            delete static_cast<const T*>(this); //如果减掉后引用计数为0, 删掉该引用
        }
}
    inline int32_t getStrongCount() const {
        return mCount.load(std::memory_order_relaxed);
    }
    private:
    mutable std::atomic<int32_t> mCount;
};
int main(int argc, char** argv)
{
    //自定义LightClass 继承LightRefBase
    LightClass* pLightClass = new LightClass();
    //调用① sp的一个参数的构造函数
    sp<LightClass> lpOut = pLightClass;
    //pLightClass 引用计数+1, 所以下面输出 1
    printf("Light Ref Count: %d.\n", pLightClass->getStrongCount());
 
    {
        //调用② sp的另一个构造函数
        sp<LightClass> lpInner = lpOut;
        //上面pLight的引用计数+1, 所以这里输出2
        printf("Light Ref Count: %d.\n", pLightClass->getStrongCount());
    }
    //上面作用域结束所以, lpInner调用析构函数③
    //pLightClass引用计数-1, 这里输出 1
    printf("Light Ref Count: %d.\n", pLightClass->getStrongCount());
 
    return 0;            
}

//StrongPointer.h
//① 
template<typename T>
sp<T>::sp(T* other) //other在上面的例子为pLightClass
        : m_ptr(other) {
    if (other)
        //调用LightRefBase的incStrong, LightRefBase的mCount+1;
        other->incStrong(this);
}
//②
template<typename T>
sp<T>::sp(const sp<T>& other) //other参数在上面的例子中为lpOut
        : m_ptr(other.m_ptr) { //other.m_ptr为 pLightClass, m_ptr其实就是pLightClass的引用
    if (m_ptr)
        m_ptr->incStrong(this); //引用计数+1
}
//③
template<typename T>
sp<T>::~sp() {
    if (m_ptr) //m_ptr为pLightClass的引用
        m_ptr->decStrong(this);
}

## RefBase

# RefBase原型
//RefBase.h
class RefBase
{
    private:
        //weakref_impl为RefBase的内部类weakref_type的实现类, 
        //mRefs包含强引用计数, 弱引用计数, flag, 以及指向外部类RefBase的指针mBase
        weakref_impl* const mRefs;  
    protected:
        RefBase(); //构造函数中 new weakref_impl()
        virtual ~RefBase(); //析构做了较多工作
        //! Flags for extendObjectLifetime()
        enum { //没有了forever
            OBJECT_LIFETIME_STRONG  = 0x0000, //对象受强引用控制, 默认
            OBJECT_LIFETIME_WEAK    = 0x0001, //对象受弱引用控制
            OBJECT_LIFETIME_MASK    = 0x0001
        };
    public:
        void incStrong(const void* id) const;
        void decStrong(const void* id) const;
        weakref_type*   createWeak(const void* id) const;
    //...省略
}

上面是RefBase中的几个重要函数声明, 接下来是weakref_impl的声明

# weakref_type, weakref_impl原型
//RefBase.h
class weakref_type
{
public:
    void incWeak(const void* id);
    void decWeak(const void* id);
    bool attemptIncStrong(const void* id);
    //..省略
}
//RefBase.cpp
class RefBase::weakref_impl : public RefBase::weakref_type //weakref_type定义了几个函数
{
public:
    std::atomic<int32_t>    mStrong; //强引用计数
    std::atomic<int32_t>    mWeak;   //弱引用计数
    RefBase* const          mBase;   //引用外部指针
    std::atomic<int32_t>    mFlags;  //标记
    //..省略空方法
}

后面都是控制weakref_impl对象, 这里只要记住有四个变量, 和加减引用计数的方法, 接下来先看下它们的实现

# weakref_type, weakref_impl实现
//RefBase.cpp
weakref_impl(RefBase* base)
    : mStrong(INITIAL_STRONG_VALUE) //强引用计数默认值
    , mWeak(0)  //弱引用计数0
    , mBase(base) //引用外部对象 RefBase
    , mFlags(0){} //flag默认0, 表示受强引用控制
void RefBase::weakref_type::incWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->addWeakRef(id); //空方法
    const int32_t c __unused = impl->mWeak.fetch_add(1, //弱引用计数+1
            std::memory_order_relaxed);
}
void RefBase::weakref_type::decWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->removeWeakRef(id); //空方法
    const int32_t c = impl->mWeak.fetch_sub(1, std::memory_order_release); //弱引用-1
    if (c != 1) return; //减1后弱引用计数不为0, 直接返回
    //弱引用计数为0, 接着往下执行
    //弱引用计数>=强引用计数
    atomic_thread_fence(std::memory_order_acquire);
    int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
    if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) { 
        // 受强引用计数影响, 默认
        if (impl->mStrong.load(std::memory_order_relaxed)
                == INITIAL_STRONG_VALUE) {
            //如果强引用计数为初始值, 回收RefBase
            delete impl->mBase;
        } else {
            //强引用计数为0, 回收weakref_impl
            delete impl;
        }
    } else {
        // 受弱引用计数控制, 回收RefBase
        impl->mBase->onLastWeakRef(id);
        delete impl->mBase;
    }
}

bool RefBase::weakref_type::attemptIncStrong(const void* id)
{
    //该方法是, 弱引用变为强引用, 所以强引用计数+1, 弱引用计数也需要+1
    //这里弱引用计数先+1, 如果变为强引用失败, 则再-1
    incWeak(id);
    
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    int32_t curCount = impl->mStrong.load(std::memory_order_relaxed);
    
    //下面判断成立, 说明已经有强引用, 说明可以, 升级为强引用
    //while为了解决多线程的问题
    while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
        if (impl->mStrong.compare_exchange_weak(curCount, curCount+1,
                std::memory_order_relaxed)) {
            break;
        }
    }
    
    if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
        // 两种情况
        // - 没有过强引用
        // - 或者强引用都被回收了
        int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
        if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
            // 默认受强引用控制时
            // 当最后的强引用被释放了, 所以curCount<=0
            if (curCount <= 0) {
                // 强引用<=0 肯定是从1减到了0, 根据decStrong()方法, 受强引用控制时, 释放RefBase
                // 所以不能升级为强引用
                decWeak(id); //弱引用计数-1, 因为上面加过1
                return false;
            }

            //curCount为初始值, 说明没有过强引用, 可以尝试一下
            while (curCount > 0) {
                //mStrong + 1
                if (impl->mStrong.compare_exchange_weak(curCount, curCount+1,
                        std::memory_order_relaxed)) {
                    break;
                }
            }
            if (curCount <= 0) {
                // 其他线程破坏了这次的升级, promote()失败
                decWeak(id);
                return false;
            }
        } else {
            // 受弱引用控制
            // onIncStrongAttempted()默认为true, 但是可以重写该方法
            // 能否promote()成功取决于开发者.
            if (!impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id)) {
                decWeak(id);
                return false;
            }
            // 可以升级为强引用, 强引用计数+1
            curCount = impl->mStrong.fetch_add(1, std::memory_order_relaxed);
            // 多线程问题, 别的线程动了强引用计数
            if (curCount != 0 && curCount != INITIAL_STRONG_VALUE) {
                impl->mBase->onLastStrongRef(id);
            }
        }
    }
    impl->addStrongRef(id);// 空方法
    // 修正强引用计数为1
    if (curCount == INITIAL_STRONG_VALUE) {
        impl->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
                std::memory_order_relaxed);
    }

    return true;
}
# RefBase实现
//RefBase.cpp
RefBase::RefBase() //无参构造函数
    : mRefs(new weakref_impl(this)){}
RefBase::~RefBase() //析构函数
{
    if (mRefs->mStrong.load(std::memory_order_relaxed)
            == INITIAL_STRONG_VALUE) {
        //没有用过强引用, 删除weakref_impl
        delete mRefs;
    } else {
        int32_t flags = mRefs->mFlags.load(std::memory_order_relaxed);
        if ((flags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
            if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) {
                //受弱引用控制, 并且若引用计数 = 0, 删除weakref_impl
                delete mRefs;
            }
        }
    }
    // for debugging purposes, clear this.
    const_cast<weakref_impl*&>(mRefs) = NULL;
}

//wp中需要调用
RefBase::weakref_type* RefBase::createWeak(const void* id) const
{
    mRefs->incWeak(id);
    return mRefs;
}
//incStrong
  void RefBase::incStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->incWeak(id); //弱引用计数+1
    refs->addStrongRef(id); //空方法
    //强引用+1
    const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
    if (c != INITIAL_STRONG_VALUE)  {
        return;
    }
    //强引用默认值为1<<28, 减去1<<28, 现在值为1
    int32_t old = refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
            std::memory_order_relaxed);
    refs->mBase->onFirstRef();
}
  void RefBase::decStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->removeStrongRef(id);//空方法
    //强引用-1
    const int32_t c = refs->mStrong.fetch_sub(1, std::memory_order_release);
    if (c == 1) { //减去后强引用计数 = 0
        std::atomic_thread_fence(std::memory_order_acquire);
        refs->mBase->onLastStrongRef(id);//可继承
        int32_t flags = refs->mFlags.load(std::memory_order_relaxed);
        if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
            //受强引用计数控制, 默认, 删掉RefBase, 并且调用RefBase的析构函数
            delete this;
        }
    }
    refs->decWeak(id);
}
  • RefBase::RefBase()

    new weakref_impl(), weakref_impl初始化

  • RefBase::~RefBase()

    强引用计数为初始值 || (受弱引用控制&&弱引用计数==0) -> 删掉weakref_impl

  • RefBase::incStrong()

    调用 weakref_type::incWeak (弱引用+1)

    强引用+1(如果第一次加1, 那么减掉初始值, 最终为1),

  • RefBase::decStrong()

    强引用-1, 减去后如果强引用计数为0, 并且受强引用控制, 释放RefBase(实际对象)

    调用 weakref_type::decWeak (弱引用-1, 还有其他逻辑)

  • RefBase::weakref_type::incWeak()

    强引用+1

  • RefBase::weakref_type::decWeak()

    弱引用-1, 减去后如果弱引用计数为0, 分两种情况, 受强引用控制, 受弱引用控制

    其实弱引用计数为0, 不管受强引用还是弱引用控制, RefBase和weakref_impl都需要释放, 下面的判断是为了不重复释放

    1. 受强引用控制, 强引用计数为初始值, 释放RefBase, 不为初始值, 释放weakref_impl

      1. 强引用计数为初始值, 释放RefBase, RefBase调用析构函数, 释放weakref_impl

      2. 强引用计数不为初始值说明, 调用过decStrong(), 并且受强引用控制, 所以会释放RefBase, 这里只需再释放weakref_impl就可以了

    2. 受弱引用控制, 释放RefBase

      受弱引用控制, 释放RefBase, RefBase调用析构函数, 释放weakref_impl

  • RefBase::weakref_type::attemptIncStrong()

    不考虑多线程的情况下, 首先如果已经有强引用, 那么可以直接升级强引用.

    当强引用<=0, 或者没有初始化过强引用时分两种情况, 受强引用或者弱引用控制

    1. 受强引用控制

      1. 强引用<=0, 说明RefBase已经被释放了, 升级失败

      2. 强引用为默认值, 说明没有过强引用, 可以升级

    2. 受弱引用控制

      首先判断开发者是否希望可以升级, 默认为true, 升级OK

RefBase的重要函数都说明完了, 接下来是strong pointer和 weak pointer, 如果上面的RefBase弄明白了, sp和wp就很简单, 只要关注它们的构造函数和析构函数, 加上wp的promote()函数即可.

## sp和wp

# sp实现
//StrongPointer.h
template<typename T>
class sp {
public:
    inline sp() : m_ptr(0) { }
    
    //构造方法很多, 其他也都一样调用RefBase的incStrong()函数
    template<typename T>
    sp<T>::sp(const sp<T>& other)
        : m_ptr(other.m_ptr) {
        if (m_ptr)
            m_ptr->incStrong(this);
    }
        
    //析构函数
    template<typename T>
    sp<T>::~sp() {
        if (m_ptr)
            m_ptr->decStrong(this);
    }
    
  
    // 特殊! 用于ProcessState, 不关注
    void force_set(T* other);
  
    // 操作符重载 sp可以自由使用引用对象
    inline  T&      operator* () const  { return *m_ptr; }
    inline  T*      operator-> () const { return m_ptr;  }
    inline  T*      get() const         { return m_ptr; }
    
    // 也是为了 sp自由使用引用对象, 宏定义就不贴了
    COMPARE(==)
    COMPARE(!=)
    COMPARE(>)
    COMPARE(<)
    COMPARE(<=)
    COMPARE(>=)

private:    
    template<typename Y> friend class sp;
    template<typename Y> friend class wp;
    void set_pointer(T* ptr) { m_ptr = ptr; }
    T* m_ptr; //引用对象
};

这里只需明白3点:

  1. 构造函数调用 incStrong(), 强引用+1, 弱引用+1
  2. 析构函数调用 decStrong(), 强引用-1, 弱引用-1 (还有其他一些逻辑)
  3. sp可以自由操作引用对象
# wp实现
//RefBase.h
template <typename T>
class wp
{
public:
template<typename T> //构造函数
    wp<T>::wp(T* other): m_ptr(other)
    {
        //createWeak()方法很简单, 上面有实现, 只是调用下incWeak, 返回weakref_impl对象      
        if (other) m_refs = other->createWeak(this);
    }
template<typename T> //析构函数
    wp<T>::~wp()
    {
        if (m_ptr) m_refs->decWeak(this);
    }
template<typename T>
    sp<T> wp<T>::promote() const //重点方法, wp升级sp
    {
        sp<T> result;
        if (m_ptr && m_refs->attemptIncStrong(&result)) {
        result.set_pointer(m_ptr);
    }
    return result; //如果升级失败, 引用对象为空
}  
private:
template<typename Y> friend class sp;
template<typename Y> friend class wp;
T*              m_ptr; //引用对象
weakref_type*   m_refs; //RefBase中的weakref_impl, 因为要调用weakref_impl的方法
};

wp的要明白4点:

  1. 构造函数调用 createWeak(), 弱引用+1
  2. 析构函数调用 decWeak() 弱引用-1 (还有其他一些逻辑)
  3. wp不可以自由操作引用对象
  4. wp的promote()方法, 可以升级为sp, 但是如果升级失败sp的引用对象为空, 所以需要做判断

OK, 智能指针的基本方法都已经讲清楚, 这里用老罗的例子实践一下.

class WeightClass : public RefBase
{
public:
    void printRefCount()
    {
        int32_t strong = getStrongCount();
        weakref_type* ref = getWeakRefs();
        printf("-----------------------\n");
        printf("Strong Ref Count: %d.\n", strong); //打印强引用计数
        printf("Weak Ref Count: %d.\n", ref->getWeakCount()); //打印弱引用计数
        printf("-----------------------\n");
    }
};

class StrongClass : public WeightClass
{
public:
    StrongClass()
    {
        printf("Construct StrongClass Object.\n");
    }
    
    virtual ~StrongClass()
    {
        printf("Destory StrongClass Object.\n");
    }
};

class WeakClass : public WeightClass
{
public:
    WeakClass()
    {
        extendObjectLifetime(OBJECT_LIFETIME_WEAK); //受弱引用控制
        printf("Construct WeakClass Object.\n");
    }
    
    virtual ~WeakClass()
    {
        printf("Destory WeakClass Object.\n");
    }
};

void TestStrongClass(StrongClass* pStrongClass)
{
    wp<StrongClass> wpOut = pStrongClass; //弱引用计数 +1
    pStrongClass->printRefCount();
    
    {
        sp<StrongClass> spInner = pStrongClass; //强引用计数+1, 弱引用计数+1
        pStrongClass->printRefCount();
    }//调用sp的析构函数, 强引用 = 0, 弱引用 = 1, 因受强引用控制, 所以对象被删除
    
    sp<StrongClass> spOut = wpOut.promote(); //升级失败
    printf("spOut: %p.\n", spOut.get());
}

void TestWeakClass(WeakClass* pWeakClass)
{
    wp<WeakClass> wpOut = pWeakClass; //弱引用计数 +1
    pWeakClass->printRefCount();
    
    {
        sp<WeakClass> spInner = pWeakClass; //强引用计数+1, 弱引用计数+1
        pWeakClass->printRefCount();
    }//调用sp的析构函数, 强引用 = 0, 弱引用 = 1, 因受弱引用控制, 所以对象不会被删除
    
    pWeakClass->printRefCount();
    sp<WeakClass> spOut = wpOut.promote(); //升级成功
    printf("spOut: %p.\n", spOut.get());
}

int main(int argc, const char * argv[]) {
    
    printf("Test Strong Class: \n");
    StrongClass* pStrongClass = new StrongClass();
    TestStrongClass(pStrongClass);
    
    printf("\nTest Weak Class: \n");
    WeakClass* pWeakClass = new WeakClass();
    TestWeakClass(pWeakClass);

    return 0;
}
//输出:
/*
Test Strong Class: 
Construct StrongClass Object.
-----------------------
Strong Ref Count: 268435456.
Weak Ref Count: 1.
-----------------------
-----------------------
Strong Ref Count: 1.
Weak Ref Count: 2.
-----------------------
Destory StrongClass Object.
spOut: 0x0.


Test Weak Class: 
Construct WeakClass Object.
-----------------------
Strong Ref Count: 268435456.
Weak Ref Count: 1.
-----------------------
-----------------------
Strong Ref Count: 1.
Weak Ref Count: 2.
-----------------------
-----------------------
Strong Ref Count: 0.
Weak Ref Count: 1.
-----------------------
spOut: 0x100300060.
Destory WeakClass Object.
*/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容