Android智能指针sp wp详解(3)

3》上面是定义一个sp指针,下面看看定义一个wp指针式如何实现的。
     wp<BBinder>  BB_wp_ptr(BB_ptr);
    下面是wp类对应上面定义类型的构造函数
   template<typename T>
   wp<T>::wp(const sp<T>& other)
       : m_ptr(other.m_ptr)
   {
       if (m_ptr) {
           m_refs = m_ptr->createWeak(this);
       }
   }
   this指针是指向wp对象的。createWeak()函数是RefBase类的成员函数。
   RefBase::weakref_type* RefBase::createWeak(const void* id) const
   {
       mRefs->incWeak(id);
       return mRefs;
   }
   mRefs指向的是第二步骤中产生的weakref_impl对象,调用基类weakref_type的成员函数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);
     /* impl->mWeak有加1,但返回值为操作前的结果 */
       LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
   }
   


三、sp、wp释放过程
  sp<BBinder> BB_SP_ptr(BB_ptr);
  实际上BB_SP_ptr和前面的BB_ptr一样,指向的是同一个BBinder对象。另外需要注意的时,调用sp构造函数:
  template<typename T>
  sp<T>::sp(const sp<T>& other)
      : m_ptr(other.m_ptr)
  {
      if (m_ptr) m_ptr->incStrong(this);
  }
  同样是需要调用BBinder对象的incStrong()函数,使用weakref_impl对象来管理新添加进来的强引用,同时增加一个
  ref_entry结构体到weakref_impl对象的mStrongRefs,增加2个ref_entry结构体到weakref_impl对象的mWeakRefs。
  如上图所示。
  
  现在来看看释放sp、wp指针的情况。
  delete BB_SP_ptr;
  将会调用如下形式的sp析构函数:
  template<typename T>
  sp<T>::~sp()
  {
      if (m_ptr) m_ptr->decStrong(this);
  }
  m_ptr指向的是前面生成的BBinder对象,调用其基类函数decStrong(this),this值是指向BB_SP_ptr对象。
  
  void RefBase::decStrong(const void* id) const
  {
      weakref_impl* const refs = mRefs;
      refs->removeStrongRef(id); // 注释3,移除mStrongRefs链表中和该sp对应的ref_entry结构体
      const int32_t c = android_atomic_dec(&refs->mStrong);
    /* 强引用计数减1, 但返回的是操作之前的引用计数值 */
      LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
      if (c == 1) {
       /*  c == 1说明刚刚removeStrongRef之前,整个系统中只存在一个sp对象引用目标对象,现在的情况就是
          系统中没有任何强指针对象来引用目标对象了,此时目标对象就会被删除释放
        */
          const_cast<RefBase*>(this)->onLastStrongRef(id);
          if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
              delete this; // mFlags =0 ,条件成立,删除目标对象,这里就会删除前面new出来的BBinder对象
          }
      }// 如果此时还有其他指向该目标对象的sp指针存在的话,就不会删除目标对象
     
      refs->removeWeakRef(id);
      refs->decWeak(id);
      /* 删除新建目标对象sp指针时在mWeakRefs链表上增加的两个ref_entry结构体 */
  }
  /*********************************注释3*********************************/
  void removeStrongRef(const void* id)
    {
        if (!mRetain) // mRetain 初始化成 flase
            removeRef(&mStrongRefs, id); 
            /* 删除mStrongRefs链表中对应id的ref_entry一项 */
      /* 也就是取消了该sp对象和目标对象的联系 */
        else
            addRef(&mStrongRefs, id, -mStrong);
    }
  
  void removeRef(ref_entry** refs, const void* id)
    {
        if (mTrackEnabled) {
            AutoMutex _l(mMutex);
           
            ref_entry* ref = *refs;
            while (ref != NULL) {
                if (ref->id == id) {
                    *refs = ref->next;
                    delete ref;
                    return;
                }
                refs = &ref->next;
                ref = *refs;
            }
        }
    }
  /*********************************注释3*********************************/
  
  delete BB_wp_ptr;
  这是删除目标对象的一个wp指针,会调用wp的析构函数:
  template<typename T>
  wp<T>::~wp()
  {
      if (m_ptr) m_refs->decWeak(this);
  }
  调用weakref_type类的decWeak()函数,如下:
  void RefBase::weakref_type::decWeak(const void* id)
  {
      weakref_impl* const impl = static_cast<weakref_impl*>(this);
      impl->removeWeakRef(id);// 移除weakref_impl对象mWeakRefs链表中对应id的ref_entry结构体
      const int32_t c = android_atomic_dec(&impl->mWeak);// 引用计数减1
      LOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
      if (c != 1) return; // c == 1, 说明这是系统中存在的指向目标对象的最后一个wp指针
     
      if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
          if (impl->mStrong == INITIAL_STRONG_VALUE)
              delete impl->mBase;
              // delete impl; 是不是应该加上这么一句,防止用户新建了wp后,不用,马上又删除的情况呢?
        /* 当目标对象的最后一个wp被析构时,如果目标对象还没有建立任何一个sp,那么目标对象被删除 */
          else {
              delete impl;
        /* 当目标对象的最后一个wp被析构时,但此时和目标对象相关的sp全部被析构,那么impl->mStrong = 0
            在最后一个sp被析构的时候,目标对象也被释放,所以此时只需要释放weakref_impl对象即可
        */
          }
      } else {
          impl->mBase->onLastWeakRef(id);
          if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
              delete impl->mBase;
          }
      }
  }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwxxfd.html