C++层Binder——智能指针

C++层Binder——智能指针

  要讲native层的Binder机制,那得首先搞明白native层智能指针的原理。

  core/include/utils/RefBase.h

  core/libutils/RefBase.cpp

  core/libutils/include/utils/StrongPointer.h

一、RefBase

  一个对象想要使用智能指针,该对象则必须要满足一个前提条件,即该对象必须继承自RefBase。这很好理解,智能指针的原理便是有一个引用计数用于计算该对象被引用的次数,而这个引用计数显然是应该被存储到被引用对象里面的。是的,这个引用计数正式在RefBase里面。

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

    weakref_impl* const mRefs;
};

  是的,这个weakref_impl正是引用计数的管理类。

class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
    std::atomic<int32_t>    mStrong;
    std::atomic<int32_t>    mWeak;
    RefBase* const          mBase;
    std::atomic<int32_t>    mFlags;
    ……
}

  mStrong是强引用计数,mWeak是弱引用计数,mBase则是引用对象所在指针。
  回到RefBase类来,RefBase类还有两个关键函数,分别是incStrong和decStrong,用于增加强引用计数和减少强引用计数。

void RefBase::incStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->incWeak(id);  //先增加一次弱引用计数
    
    refs->addStrongRef(id); //虽然看函数名是增加强引用数,但实际该函数中什么也没做
    const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);    //真正增加强引用计数的地方
    ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
#if PRINT_REFS
    ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
    if (c != INITIAL_STRONG_VALUE)  { //若c != INITIAL_STRONG_VALUE说明该对象不是第一次被引用,INITIAL_STRONG_VALUE是mStrong的初值
        return; //不是第一次被引用,直接退出函数
    }
    //否则是第一次被引用,会调用onFirstRef接口
    int32_t old __unused = refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE, std::memory_order_relaxed);
    // A decStrong() must still happen after us.
    ALOG_ASSERT(old > INITIAL_STRONG_VALUE, "0x%x too small", old);
    refs->mBase->onFirstRef();
}

void RefBase::decStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->removeStrongRef(id); //什么都没做
    const int32_t c = refs->mStrong.fetch_sub(1, std::memory_order_release); //真正减少强引用计数的地方
#if PRINT_REFS
    ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
    LOG_ALWAYS_FATAL_IF(BAD_STRONG(c), "decStrong() called on %p too many times",
            refs);
    if (c == 1) {   //强引用计数只剩下一个时,执行下面逻辑,会调用被引用用对象的onLastStrongRef方法
        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) {
            delete this;
            // The destructor does not delete refs in this case.
        }
    }
    // Note that even with only strong reference operations, the thread
    // deallocating this may not be the same as the thread deallocating refs.
    // That's OK: all accesses to this happen before its deletion here,
    // and all accesses to refs happen before its deletion in the final decWeak.
    // The destructor can safely access mRefs because either it's deleting
    // mRefs itself, or it's running entirely before the final mWeak decrement.
    //
    // Since we're doing atomic loads of `flags`, the static analyzer assumes
    // they can change between `delete this;` and `refs->decWeak(id);`. This is
    // not the case. The analyzer may become more okay with this patten when
    // https://bugs.llvm.org/show_bug.cgi?id=34365 gets resolved. NOLINTNEXTLINE
    refs->decWeak(id);  //减少弱引用计数
}

  以上是增加和减少弱引用计数的调用方法,有趣的是,RefBase类中,只有修改强引用计数的方法,但修改弱有引用的地方只有一处createWeak方法,该方法实际上也是调用的weakref_type中的incWeak。

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

  所以本质上修改弱引用计数的方法在weakref_type类中,该类是weakref_impl的父类,而weakref_impl正式引用计数的管理类。那么使用wp对RefBase进行弱引用时,又是怎么修改RefBase的弱引用计数呢?

二、wp

  当使用wp引用RefBase及其子类时,wp会从RefBase中直接获取weakref_impl并存储到自己的m_refs成员变量中。


template <typename T>
class wp
{
    ……

    weakref_type*   m_refs;
};

  然后有两个方式增加弱引用,一是直接调用weakref_type的incWeak和decWeak对弱引用计数进行操作。二是调用RefBase的createWeak方法。

template<typename T>
wp<T>::wp(T* other)
    : m_ptr(other)
{
    //other不是wp类型,说明是第一次引用,且不为空时,
    m_refs = other ? m_refs = other->createWeak(this) : nullptr;
}

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)
{
    m_refs = m_ptr ? m_ptr->createWeak(this) : nullptr;
}

template<typename T>
wp<T>::~wp()
{
    if (m_ptr) m_refs->decWeak(this); //减少弱引用的方法只有调用RefBase的decWeak
}

三、sp

  sp的成员变量只有一个m_ptr,而m_ptr本质上是被引用的RefBase子类。

class sp {
    ……
    T* m_ptr;
};

  在sp的构造和析构函数中,会分别增加、减少RefBase的强引用计数。而其调用的方法则是RefBase中的incStrong和decStrong

template<typename T>
sp<T>::sp(T* other)
        : m_ptr(other) {
    if (other) {
        check_not_on_stack(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);
}

template <typename T>
sp<T>::sp(sp<T>&& other) noexcept : m_ptr(other.m_ptr) {
    other.m_ptr = nullptr;
}

template<typename T> template<typename U>
sp<T>::sp(U* other)
        : m_ptr(other) {
    if (other) {
        check_not_on_stack(other);
        (static_cast<T*>(other))->incStrong(this);
    }
}

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

template<typename T> template<typename U>
sp<T>::sp(sp<U>&& other)
        : m_ptr(other.m_ptr) {
    other.m_ptr = nullptr;
}

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

四、UML

  Android C++的智能指针UML图如下所示
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值