Android中的智能指针:sp和wp

原文:

Android中的sp和wp指针

链接:http://blog.csdn.net/DroidPhone/article/details/5799792


经常会在android的framework代码中发现sp和wp这样的指针,平时看的时候都把他当成一个普通的指针封装过掉了,这几天终于忍不住了,想深入了解一下。

 

相关的代码:

frameworks/base/include/utils/RefBase.h

frameworks/base/libs/utils/RefBase.cpp

 

sp和wp都是一个模板类,看一下sp类的定义:

[cpp] view plain copy
  1. template <typename T>  
  2. class sp  
  3. {  
  4. public:  
  5.     typedef typename RefBase::weakref_type weakref_type;  
  6.     inline sp() : m_ptr(0) { }  
  7.     sp(T* other);  
  8.     sp(const sp& other);  
  9.     ~sp();  
  10.     ......  
  11. private:      
  12.     // Optimization for wp::promote().  
  13.     sp(T* p, weakref_type* refs);  
  14.       
  15.     T*              m_ptr;  
  16. };  

 

可以看到他确实封转了一个原生指针T* m_ptr. 再看一下其中一个构造函数和析构函数:

 

[c-sharp] view plain copy
  1. template  
  2. sp::sp(T* other)  
  3.     : m_ptr(other)  
  4. {  
  5.     if (other) other->incStrong(this);  
  6. }  
  7.   
  8. template  
  9. sp::~sp()  
  10. {  
  11.     if (m_ptr) m_ptr->decStrong(this);  
  12. }  

 

咋一看好奇怪,因为在构造函数中调用了incStrong(),在析构函数中调用的decStrong(),显然是管理引用计数的函数,但是sp类的中并没有定义这两个函数,这两个函数是在RefBase类中定义的,由此可以得出结论:

要想使用sp或者wp, T必需要继承RefBase类才行

 

RefBase的静态关系如下:

 

 

 

 其中weakref_type是RefBase的内嵌类,weakref_impl则是weakref_type的子类,RefBase的大部分工作都是交由weakref_impl类来完成,通过RefBase的成员变量weakref_impl* const mRefs。查看其中一个sp的构造函数:

 

[c-sharp] view plain copy
  1. template  
  2. sp::sp(T* other)  
  3.     : m_ptr(other)  
  4. {  
  5.     if (other) other->incStrong(this);  
  6. }  

 

建立sp的动态关系如下:

sp

  --> RefBase : incStrong()

  -->weakref_impl : addStrongRef()

  -->android_atomic_inc(&refs->mStrong)

 

可见当一个普通指针变成一个sp指针后,将会由RefBase类维护该指针的引用计数,当引用为零时则自动释放该指针指向的内存:

[c-sharp] view plain copy
  1. void RefBase::decStrong(const void* id) const  
  2. {  
  3.     weakref_impl* const refs = mRefs;  
  4.     refs->removeStrongRef(id);  
  5.     const int32_t c = android_atomic_dec(&refs->mStrong);  
  6.     if (c == 1) {  
  7.         const_cast(this)->onLastStrongRef(id);  
  8.         if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {  
  9.             delete this;    //引用为0,销毁  
  10.         }  
  11.     }  
  12.     refs->removeWeakRef(id);  
  13.     refs->decWeak(id);  
  14. }  

 

 wp是怎么一回事?

wp其实是弱指针的意思,wp类型不能直接对类型T进行操作,要想对T进行某种操作,必需把wp升级为sp指针,使用promote()来实现升级:

        wp weakp= new T();

        sp t = weakp.promote();

wp可能会在弱引用计数不为0的情况下被销毁,执行如下代码:

 

[c-sharp] view plain copy
  1. class WPTest : public RefBase {  
  2. public:  
  3.     WPTest(){  
  4.         LOGD("WPTest constructor");  
  5.     }  
  6.     virtual ~WPTest() {  
  7.         LOGD("WPTest destructor");  
  8.     }  
  9.   
  10.     virtual void onFirstRef() {  
  11.         LOGD("first weak ptr ref callback");  
  12.     }  
  13.   
  14.     virtual void onLastStrongRef(const void* id) {  
  15.         LOGD("last strong ptr ref callback");  
  16.     }  
  17.   
  18.     virtual void onLastWeakRef(const void* id) {  
  19.         LOGD("last weak ptr ref callback");  
  20.     }  
  21. };  
  22.   
  23.   
  24. int main()  
  25. {  
  26.     WPTest *T = new WPTest();  
  27.     {  
  28.         wp weakp(T);  
  29.   
  30.         {  
  31.             LOGD("promote to strong ptr.../n");  
  32.   
  33.             sp strongp = weakp.promote();  
  34.   
  35.             LOGD("strong ptr's lifetime is just about to finish .../n");  
  36.         }  
  37.   
  38.         LOGD("weak ptr's lifetime is just about to finish .../n");  
  39.     }  
  40.   
  41.     LOGD("weak ptr is out of scope./n");  
  42.   
  43.     return 0;  
  44. }  

程序打印的结果是:

D/sp-wp-sample(  225): WPTest constructor
D/sp-wp-sample(  225): promote to strong ptr...
D/sp-wp-sample(  225): first weak ptr ref callback
D/sp-wp-sample(  225): strong ptr's lifetime is just about to finish ...
D/sp-wp-sample(  225): last strong ptr ref callback
D/sp-wp-sample(  225): WPTest destructor
D/sp-wp-sample(  225): weak ptr's lifetime is just about to finish ...
D/sp-wp-sample(  225): weak ptr is out of scope.

由此可见虽然wp的生命周期还没有结束,但是因为升级为sp后,sp的强引用计数为0,导致WPTest 被销毁,当强引用为0而弱引用不为0时,WPTest 销毁时,基类RefBase的mRefs指向的weakref_impl类并没有释放,从而保证了弱引用可以继续起作用,这点可以从RefBase的析构函数中看出来:

[c-sharp] view plain copy
  1. RefBase::~RefBase()  
  2. {  
  3. //    LOGV("Destroying RefBase %p (refs %p)/n", this, mRefs);  
  4.     if (mRefs->mWeak == 0) {  
  5. //        LOGV("Freeing refs %p of old RefBase %p/n", mRefs, this);  
  6.         delete mRefs;  
  7.     }  
  8. }  

 

不过也可以改变这一行为,我们修改一下WPTest的构造函数:

[c-sharp] view plain copy
  1. WPTest(){  
  2.         LOGD("WPTest constructor");  
  3.         extendObjectLifetime(OBJECT_LIFETIME_WEAK);  
  4.     }  

 

这时的打印结果是:

D/sp-wp-sample(  217): WPTest constructor
D/sp-wp-sample(  217): promote to strong ptr...
D/sp-wp-sample(  217): first weak ptr ref callbac
D/sp-wp-sample(  217): strong ptr's lifetime is j
D/sp-wp-sample(  217): last strong ptr ref callba
D/sp-wp-sample(  217): weak ptr's lifetime is j
D/sp-wp-sample(  217): last weak ptr ref callback
D/sp-wp-sample(  217): WPTest destructor
D/sp-wp-sample(  217): weak ptr is out of scope.

 

可以看出现在只有当强引用和弱引用的计数都为0时,WPTest对象才会被销毁。

原文二:

androidsp wp 【转】

链接:http://hi.baidu.com/donghaozheng/item/a605d993735602bdcc80e5e4

转自:http://wangjun-1985.spaces.live.com/blog/cns!E9070276AAF56C8E!472.entry


android 中可以广泛看到的template classSp 句柄类实际上是android 为实现垃圾回收机制的智能指针。智能指针是c++ 中的一个概念,因为c++ 本身不具备垃圾回收机制,而且指针也不具备构造函数和析构函数,所以为了实现内存( 动态存储区) 的安全回收,必须对指针进行一层封装,而这个封装就是智能指针,其实说白了,智能指针就是具备指针功能同时提供安全内存回收的一个类。当然,智能指针的功能还不只这些,想了解更多大家可以去研究下~

智能指针有很多实现方式,android 中的sp 句柄类实际上就是google实现的一种强引用的智能指针。我没有仔细看android sp 的实现方式,但其基本原理是固定的,现在我们从一个相对简单的例子来看智能指针的实现:

首先看一个最简单的对指针的封装:

Template

class SmartPtr{

public:

SmartPtr(T *p = 0):ptr(p){}

~SmartPtr(){delete ptr ;}

private:

T *ptr ;

};

通过上面的封装,我们就可以用下面的方式来使用SmartPtr 而不需要担心内存泄露的问题:

SmartPtr pointer(new int) ;

*(pointer.ptr) = 10 ;

为了方便使用,我们可以对操作符进行重载,让智能指针的操作更像是指针

T &operator*(){return *ptr}

T* operator->(){return ptr}

经过上面的重载,我们就可以像使用真正的指针一样而不需要去解决内存泄露问题。

因为智能指针封装了指针,所以必须为其实现拷贝构造函数和“=”操作符重载。因为如果不提供这两个函数,当上面的智能指针进行赋值的时候必然会使指针指向同一个区域,一旦析构的话会导致同一个指针被delete 两次。

在这里,拷贝构造函数的实现是有技巧 的,使用拷贝构造函数创建一个新的只能指针时,并不建立新的对象,而是让新的智能指针指向同一个对象,实际上就是常说的浅复制。但是这样的话就会导致多个指针指向同一块内存区域,当调用析构函数的时候如何来保证同一块内存区域只会被delete 一次呢,这里实现的方法有很多,最常用的是引数控制。即在智能指针中加入一个计数器,每次增加一个对内存区域的强引用,则计数器加一,当计数器为0 时,这个对象就可以被删除了, 这个计数器采用动态分配跟指针分开存储, 因为这个计数器是多个智能指针需要共享的:

Template

class SmartPtr{

public:

SmartPtr(T *p = 0):ptr(p){count = new int(1) ;}// 第一次创建的时候,引数肯定是1

SmartPtr(const SmartPtr & rhs):ptr(rhs.ptr),count(rhs.count){++*rhs.count ;}

T &operator*(){return *ptr}

T* operator->(){return ptr}

SmartPtr &operator=(const SmartPtr & rhs){

if(ptr == rhs.ptr)

return *this ;

if(--*count == 0){

    delete ptr ;

    delete count ;

    }

    ++*rhs.count ;

    count = rhs.count ;

    ptr = rhs.ptr ;

}

~SmartPtr(){

if(--*count==0)

delete ptr ;

delete count ;

}

private:

T *ptr ;

int *count ;

};

这样,一个智能指针就基本成形了,当然这只是最简单的智能指针,商业库提供的智能指针都提供非常强大的功能,如果能仔细研究透了android 在这方面的实现,应该在c++ 内存控制方面很有长进~~暂时还没有时间,还要顺着camera 往下看,有牛人懂的话email 多指教哈~~

出了智能指针sp 外,android 里面还出现了wp 这个指针类,实际上他是一个弱引用类型的指针类,弱引用是在.net 以及java 中经常用到的,弱引用是一个对象引用的持有者,使用弱引用后可以维持对对象的引用,但是不会阻止其被垃圾回收。如果一个对象只有弱引用了,那它就成为被垃圾回收的候选对象,就像没有剩余的引用一样,而且一旦对象被删除,所有的弱引用也会被清楚。弱引用适合那些数据成员特别多,而且重新创建又相对容易的类,也就是俗称的胖子类,建立弱引用可以引用对象,但也不阻止其被垃圾回收,在内存的使用方面取得一定的平衡。

android 中wp 类里面的promote 函数实际上就是将一个弱引用升级为一个强引用。不管是sp 还是wp ,实际上都是android 利用现有的c++ 特性来解决内存使用和回收的一种手段。


原文三:Android智能指针使用方法介绍

链接:http://developer.51cto.com/art/201001/180894.htm

Android手机操作系统既然是开源的操作系统。那么在具体的文件夹中就会存放着各种相关功能的开源代码。我们在使用的时候可以根据这些源代码进行相应的修改就能轻松的完成我们所需的功能。在这里大家就一起来看看Android智能指针的相关源码解读以及应用方法。

  • Android事件侦听器回调方法浅谈
  • Android模拟器尺寸随意改
  • 全方位解读Android多媒体框架源码
  • Android命令行启动程序正确使用技巧解析
  • Android查询联系人信息正确操作方法

Android的源代码中,经常会看到形如:sp< xxx>、wp< xxx>这样的类型定义,这其实是Android中的智能指针。智能指针是C++中的一个概念,通过基于引用计数的方法,解决对象的自动释放的问题。在C++编程中,有两个很让人头痛的问题:一是忘记释放动态申请的对象从而造成内存泄露;二是对象在一个地方释放后,又在别的地方被使用,从而引起内存访问错误。

程序员往往需要花费很大精力进行精心设计,以避免这些问题的出现。在使用智能指针后,动态申请的内存将会被自动释放(有点类似Java的垃圾回收),不需要再使用delete来释放对象,也不需要考虑一个对象是否已经在其它地方被释放了,从而使程序编写工作减轻不少,而程序的稳定性大大提高。

Android智能指针相关的源代码在下面两个文件中:

frameworks\base\include\utils\RefBase.h

frameworks\base\libs\utils\RefBase.cpp

Android中定义了两种智能指针类型,一种是强指针sp(strong pointer),一种是弱指针(weak pointer)。其实成为强引用和弱引用更合适一些。强指针与一般意义的智能指针概念相同,通过引用计数来记录有多少使用者在使用一个对象,如果所有使用者都放弃了对该对象的引用,则该对象将被自动销毁。

指针也指向一个对象,但是弱指针仅仅记录该对象的地址,不能通过弱指针来访问该对象,也就是说不能通过弱智真来调用对象的成员函数或访问对象的成员变量。要想访问弱指针所指向的对象,需首先将弱指针升级为强指针(通过wp类所提供的promote()方法)。弱指针所指向的对象是有可能在其它地方被销毁的,如果对象已经被销毁,wp的promote()方法将返回空指针,这样就能避免出现地址访问错的情况。

是不是很神奇?弱指针是怎么做到这一点的呢?其实说穿了一点也不复杂,原因就在于每一个可以被智能指针引用的对象都同时被附加了另外一个 weakref_impl类型的对象,这个对象中负责记录对象的强指针引用计数和弱指针引用计数。这个对象是Android智能指针的实现内部使用的,智能指针的使用者看不到这个对象。弱指针操作的就是这个对象,只有当强引用计数和弱引用计数都为0时,这个对象才会被销毁。

说了这么多原理,下面该看看到底智能指针该怎么使用了。假设现在有一个类MyClass,如果要使用智能指针来引用这个类的对象,那么这个类需满足下列两个前提条件:

(1) 这个类是基类RefBase的子类或间接子类;

(2) 这个类必须定义虚构造函数,即它的构造函数需要这样定义:

   
   
   
   
  1. virtual ~MyClass(); 

满足了上述条件的类就可以定义Android智能指针了,定义方法和普通指针类似。比如普通指针是这样定义:

   
   
   
   
  1. MyClass* p_obj; 

Android智能指针是这样定义:

   
   
   
   
  1. sp< MyClass> p_obj; 

注意不要定义成 sp< MyClass>* p_obj。初学者容易犯这种错误,这样实际上相当于定义了一个指针指针。尽管在语法上没有问题,但是最好永远不要使用这样的定义。

定义了一个智能指针的变量,就可以象普通指针那样使用它,包括赋值、访问对象成员、作为函数的返回值、作为函数的参数等。比如:

   
   
   
   
  1. p_obj = new MyClass();   
  2. // 注意不要写成 p_obj = new sp< MyClass> 
  3. sp< MyClass> p_objp_obj2 = p_obj;  
  4. p_obj->func();  
  5. p_obj = create_obj();  
  6. some_func(p_obj); 

注意不要试图delete一个Android智能指针,即 delete p_obj。不要担心对象的销毁问题,智能指针的最大作用就是自动销毁不再使用的对象。不需要再使用一个对象后,直接将指针赋值为NULL即可:

   
   
   
   
  1. p_obj = NULL

上面说的都是强指针,弱指针的定义方法和强指针类似,但是不能通过弱指针来访问对象的成员。下面是弱指针的示例:

   
   
   
   
  1. wp< MyClass> wp_obj = new MyClass();  
  2. p_obj = wp_obj.promote();   
  3. // 升级为强指针。不过这里要用.而不是->,真是有负其指针之名啊  
  4. wp_obj = NULL

Android智能指针用起来是很方便,在一般情况下最好使用智能指针来代替普通指针。但是需要知道一个智能指针其实是一个对象,而不是一个真正的指针,因此其运行效率是远远比不上普通指针的。所以在对运行效率敏感的地方,最好还是不要使用智能指针为好。


原文四:

Android指针管理:RefBase,SP,WP

链接:http://www.cnblogs.com/angeldevil/archive/2013/03/10/2952586.html

  Android中通过引用计数来实现智能指针,并且实现有强指针与弱指针。由对象本身来提供引用计数器,但是对象不会去维护引用计数器的值,而是由智能指针来管理。

        要达到所有对象都可用引用计数器实现智能指针管理的目标,可以定义一个公共类,提供引用计数的方法,所有对象都去继承这个公共类,这样就可以实现所有对象都可以用引用计数来管理的目标,在Android中,这个公共类就是RefBase,同时还有一个简单版本LightRefBase。

        RefBase作为公共基类提供了引用计数的方法,但是并不去维护引用计数的值,而是由两个智能指针来进行管理:sp(Strong Pointer)和wp(Weak Pointer),代表强引用计数和弱引用计数。

 

一、轻量级引用计数的实现:LightRefBase

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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 basetype;
protected :
     inline  ~LightRefBase() { }
private :
     mutable  volatile  int32_t mCount;
};

        LightRefBase的实现很简单,只是内部保存了一个变量用于保存对象被引用的次数,并提供了两个函数用于增加或减少引用计数。

 

二、sp(Strong Pointer)

        LightRefBase仅仅提供了引用计数的方法,具体引用数应该怎么管理,就要通过智能指针类来管理了,每当有一个智能指针指向对象时,对象的引用计数要加1,当一个智能指针取消指向对象时,对象的引用计数要减1,在C++中,当一个对象生成和销毁时会自动调用(拷贝)构造函数和析构函数,所以,对对象引用数的管理就可以放到智能指针的(拷贝)构造函数和析构函数中。Android提供了一个智能指针可以配合LightRefBase使用:spsp的定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
template  < typename  T>
class  sp
{
public :
     inline  sp() : m_ptr(0) { }
     sp(T* other);
     sp( const  sp& other);
                                          
     template < typename  U>sp(U* other);
     template < typename  U>sp( const  sp& other);
                                        
     ~sp();
                                          
     // Assignment
     sp& operator = (T* other);
     sp& operator = ( const  sp& other);
                                          
     template < typename  U>sp& operator = ( const  sp& 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可以精简为如下形式(赋值操作符也省略掉了,构造函数省略相似的两个):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template  < typename  T>
class  sp
{
public :
     inline  sp() : m_ptr(0) { }
     sp(T* other);
     sp( const  sp& 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& other)的实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
template < typename  T>
sp::sp(T* other)
: m_ptr(other)
{
     if  (other) other->incStrong( this );
}
                                       
template < typename  T>
sp::sp( const  sp& other)
: m_ptr(other.m_ptr)
{
     if  (m_ptr) m_ptr->incStrong( this );
}

 

        内部变量m_ptr指向实际对象,并调用实际对象的incStrong函数,T继承自LightRefBase,所以此处调用的是LightRefBase的incStrong函数,之后实际对象的引用计数加1。

        当智能指针销毁的时候调用智能指针的析构函数:

    

1
2
3
4
5
template < typename  T>
sp::~sp()
{
     if  (m_ptr) m_ptr->decStrong( this );
}

        调用实际对象即LightRefBase的decStrong函数,其实现如下:

1
2
3
4
5
inline  void  decStrong( const  void * id)  const  {
     if  (android_atomic_dec(&mCount) == 1) {
         delete  static_cast < const  T*>( this );
     }
}

        android_atomic_dec返回mCount减1之前的值,如果返回1表示这次减过之后引用计数就是0了,就把对象delete掉。

 

三、RefBase

        RefBase提供了更强大的引用计数的管理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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    = 0x0003
     };
                                     
     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  weakref_type;
     class  weakref_impl;
                                     
     RefBase( const  RefBase& o);
     RefBase&        operator=( const  RefBase& o);
     weakref_impl*  const  mRefs;
};

 

        不同于LightRefBase的是,RefBase内部并没有使用一个变量来维护引用计数,而是通过一个weakref_impl *类型的成员来维护引用计数,并且同时提供了强引用计数和弱引用计数。weakref_impl继承于RefBase::weakref_type,代码比较多,不过大都是调试代码,由宏定义分开,Release是不包含调试代码的,去除这些代码后其定义为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#define INITIAL_STRONG_VALUE (1<<28)
                                
class  RefBase::weakref_impl :  public  RefBase::weakref_type 
public
     volatile  int32_t    mStrong; 
     volatile  int32_t    mWeak; 
     RefBase*  const       mBase; 
     volatile  int32_t    mFlags; 
                                   
     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  addWeakRef( const  void /*id*/ ) { } 
     void  removeWeakRef( const  void /*id*/ ) { } 
     void  printRefs()  const  { } 
     void  trackMe( bool bool ) { } 
};

        weakref_impl中的函数都是作为调试用,Release版的实现都是空的,成员变量分别表示强引用数、弱引用数、指向实际对象的指针与flag,flag可控制实际对象的生命周期,取值为0或RefBase中定义的枚举值。

        RefBase提供了incStrong与decStrong函数用于控制强引用计数值,其弱引用计数值是由weakref_impl控制,强引用计数与弱引用数都保存在weakref_impl *类型的成员变量mRefs中。

        RefBase同LightRefBase一样为对象提供了引用计数的方法,对引用计数的管理同样要由智能指针控制,由于RefBase同时实现了强引用计数与弱引用计数,所以就有两种类型的智能指针sp(Strong Pointer)与wp(Weak Pointer)。

 

        sp前面已经说过,其(拷贝)构造函数调用对象即RefBase的incStrong函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
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  (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。

        成员变量mRefs是在对象的构造函数中初始化的:

1
2
3
4
RefBase::RefBase()
     : mRefs( new  weakref_impl( this ))
{
}

        weakrel_impl的incWeak继承自父类weakrel_type的incWeak:

1
2
3
4
5
6
7
void  RefBase::weakref_type::incWeak( const  void * id)
{
     weakref_impl*  const  impl =  static_cast
     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函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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  (c == 1) { 
         const_cast ( this )->onLastStrongRef(id); 
         if  ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) { 
             delete  this
         }
    
     refs->removeWeakRef(id); 
     refs->decWeak(id); 
}

        decStrong中将强引用数与弱引用数同时减1,如果这是最后一个强引用的话,会调用对象的onLastStrongRef,并且判断成员变量mRefs的成员变量mFlags来决定是否在对象的强引用数为0时释放对象。

        mFlags可以为0或以下两个枚举值:

1
2
3
4
enum  {
     OBJECT_LIFETIME_WEAK    = 0x0001,
     OBJECT_LIFETIME_FOREVER    = 0x0003
};

        mFlags的值可以通过extendObjectLifetime函数改变:

1
2
3
4
void  RefBase::extendObjectLifetime(int32_t mode)
{
     android_atomic_or(mode, &mRefs->mFlags);
}

        OBJECT_LIFETIME_FOREVER包含OBJECT_LIFETIME_WEAK(位运算中其二进制11包含01),所以当

1
refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK

        为true时表示mFlags为0,实际对象的生命周期受强引用数控制,所以在强引用数为0时delete this,否则实际对象的生命周期就由弱引用数控制。

        再来看decWeak:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void  RefBase::weakref_type::decWeak( const  void * id) 
     weakref_impl*  const  impl =  static_cast ( this ); 
     impl->removeWeakRef(id); 
     const  int32_t c =android_atomic_dec(&impl->mWeak); 
     if  (c != 1)  return
                          
     if  ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) { 
         if  (impl->mStrong == INITIAL_STRONG_VALUE) 
             delete  impl->mBase; 
         else 
             delete  impl; 
        
     else 
         impl->mBase->onLastWeakRef(id); 
         if  ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) { 
             delete  impl->mBase; 
        
    
}

        将弱引用数减1,若减1后不为0直接返回,否则判断

1
(impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
    1. 判断结果为true:

实际对象生命周期被强引用数控制,接下来判断:

1
mpl->mStrong == INITIAL_STRONG_VALUE
    1. 如果判断为true表示对象只被弱引用引用过,现在弱引用数为0,直接删除实际对象。

    2. 如果判断为false,表示对象曾经被强引用引用过,但现在强引用为变为0了(因为增加或减小强引用数时一定同时增加或减小弱引用数,所以弱引用数为0时,强引用数一定为0),弱引用数为0了,直接释放mRefs,而实际对象由于受强引用数控制,已经在RefBase::decStrong中被delete了。

  1. 判断结果为false:

    判断mFlgs是否是OBJECT_LIFETIME_FOREVER,如果是,什么都不作由用户自己控制对象的生命周期,否则,实际对象的生命周期受弱引用数控制,现在弱引用数为0,delete实际对象。

四、wp(Weak Pointer)

        定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
template  < typename  T>
class  wp
{
public :
     typedef  typename  RefBase::weakref_type weakref_type;
                     
     inline  wp() : m_ptr(0) { }
                 
     wp(T* other);
     wp( const  wp& other);
     wp( const  sp& other);
     template < typename  U> wp(U* other);
     template < typename  U> wp( const  sp& other);
     template < typename  U> wp( const  wp& other);
                 
     ~wp();
                     
     // Assignment
                 
     wp& operator = (T* other);
     wp& operator = ( const  wp& other);
     wp& operator = ( const  sp& other);
                     
     template < typename  U> wp& operator = (U* other);
     template < typename  U> wp& operator = ( const  wp& other);
     template < typename  U> wp& operator = ( const  sp& other);
                     
     void  set_object_and_refs(T* other, weakref_type* refs);
                 
     // promotion tosp
                     
     sp 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(==)
     COMPARE(!=)
     COMPARE(>)
     COMPARE(<)
     COMPARE(<=)
     COMPARE(>=)
                 
private :
     template < typename  Y>  friend  class  sp;
     template < typename  Y>  friend  class  wp;
                 
     T*              m_ptr;
     weakref_type*   m_refs;
};

        同sp一样,m_ptr指向实际对象,但wp还有一个成员变量m_refs。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
template < typename  T>
wp::wp(T* other)
     : m_ptr(other)
{
     if  (other) m_refs = other->createWeak( this );
}
                  
template < typename  T>
wp::wp( const  wp& other)
     : m_ptr(other.m_ptr), m_refs(other.m_refs)
{
     if  (m_ptr) m_refs->incWeak( this );
}
                 
RefBase::weakref_type* RefBase::createWeak( const  void * id)  const
{
     mRefs->incWeak(id);
     return  mRefs;
}

        可以看到,wp的m_refs就是RefBase即实际对象的mRefs。

        wp析构的时候减少弱引用计数:

1
2
3
4
5
template < typename  T>
wp::~wp()
{
     if  (m_ptr) m_refs->decWeak( this );
}

        由于弱指针没有重载*与->操作符,所以不能直接操作指向的对象,虽然有unsafe_get函数,但像名字所示的,不建议使用,直接使用实际对象指针的话就没必要用智能指针了。

        因为弱指针不能直接操作对象,所以要想操作对象的话就要将其转换为强指针,即wp::promote方法:

1
2
3
4
5
6
7
8
9
10
11
template < typename  T>
sp wp::promote()  const
{
     return  sp(m_ptr, m_refs);
}
                
template < typename  T>
sp::sp(T* p, weakref_type* refs)
     : m_ptr((p && refs->attemptIncStrong( this )) ? p : 0)
{
}

        是否能从弱指针生成一个强指针关键是看refs->attemptIncStrong,看其定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
bool  RefBase::weakref_type::attemptIncStrong( const  void * id)
{
     incWeak(id);
                    
     weakref_impl*  const  impl =  static_cast ( 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->addWeakRef(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 ;
}

        首先通过incWeak将弱引用数加1(被强指针sp引用会导致强引用数和弱引用数同时加1),然后:

1
2
3
4
5
6
7
int32_t curCount = impl->mStrong;
while  (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
     if  (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
         break ;
     }
     curCount = impl->mStrong;
}

        如果之前已经有强引用,直接将强引用数加1,android_atomic_cmpxchg表示如果impl->mStrong的值为curCount,则把impl->mString的值改为curCount+1,此处用while循环是防止其他线程已经增加了强引用数。

   接下来:

1
if  (curCount <= 0 || curCount == INITIAL_STRONG_VALUE)

   表示对象目前没有强引用,这就要判断对象是否存在了。

   如果curCount == INITIAL_STRONG_VALUE,表示对象没有被sp引用过。接下来判断:

 

1
2
allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
     || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);

        表示:如果对象的生命周期只受强引用控制,对象一定存在,要有强引用才可以管理对象的释放,所以一定会允许生成强引用;如果对象的生命周期受弱引用控制,调用对象的onIncStrongAttempted试图增加强引用,由于此时在弱引用中,弱引用一定不为0,对象也一定存在,调用onIncStrongAttempted的意图是因为类的实现者可能不希望用强引用引用对象。在RefBase中onIncStrongAttempted默认返回true:

1
2
3
4
bool  RefBase::onIncStrongAttempted(uint32_t flags,  const  void * id)
{
     return  (flags&FIRST_INC_STRONG) ?  true  false ;
}

        如果curCount <= 0(只会等于0),表示对象强引用数经历了INITIAL_STRONG_VALUE -->大于0 --> 0,接下来就要判断:

1
2
allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK
     && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);

        如果对象的生命周期受强引用数控制,那么由于曾被sp引用过,现在强引用数又为0,对象就已经被delete了,所以就不能生成强引用,否则如果对象的生命周期受弱引用数控制,就通过onIncStrongAttempted看类的实现者是否希望当对象的强引用数变为0时可以再次被强引用引用。

1
2
3
4
if  (!allow) {
     decWeak(id);
     return  false ;
}

    如果allow为false表示不能从弱引用生成强引用,就要调用decWeak将弱引用减1(因为在promote入口先将弱引用加了1),然后返回false表示生成强引用失败。

1
2
3
4
if  (curCount == INITIAL_STRONG_VALUE) {
     android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);
     impl->mBase->onFirstRef();
}

    最后,如果curCount == INITIAL_STRONG_VALUE表示第一次被sp引用,调用对象的onFirstRef函数。

五、总结

        RefBase内部有一个指针指向实际对象,有一个weakref_impl类型的指针保存对象的强/弱引用计数、对象生命周期控制。

 

       sp只有一个成员变量,用来保存实际对象,但这个实际对象内部已包含了weakref_impl *对象用于保存实际对象的引用计数。sp 管理一个对象指针时,对象的强、弱引用数同时加1,sp销毁时,对象的强、弱引用数同时减1。

 

        wp中有两个成员变量,一个保存实际对象,另一个是weakref_impl *对象。wp管理一个对象指针时,对象的弱引用计数加1,wp销毁时,对象的弱引用计数减1。

 

        weakref_impl中包含一个flag用于决定对象的生命周期是由强引用数控制还是由弱引用数控制:

  • 当flag为0时,实际对象的生命周期由强引用数控制,weakref_impl *对象由弱引用数控制。

  • 当flag为OBJECT_LIFETIME_WEAK时,实际对象的生命周期受弱引用数控制。

  • 当flag为OBJECT_LIFETIME_FOREVER时,实际对象的生命周期由用户控制。

        可以用extendObjectLifetime改变flag的值。


原文五:Android智能指针sp wp详解(不让拷贝,只得贴上链接)

链接:http://www.360doc.com/content/11/0410/10/3700464_108552116.shtml

你可能感兴趣的:(Android中的智能指针:sp和wp)