Android 智能指针(1)

         很久没有碰C++了,用了两周时间复习了一下,感觉知识应该时常巩固,不然很容易忘掉。
        智能指针是一种能够自动维护对象引用计数的技术,用来管理C++对象的释放。因为C++不像Java有自动回收机制,C++需要程序员手动的来释放堆资源(通过New 出来的对象-----指针)。如果程序一直都不释放内存,那么长期运行,必定造成内存吃紧。如果我们手动来释放资源,我们又将面临另一个难题,当两个对象都指向同一个内存地址(同一指针对象),当其中的一个对象A删除了所指向内存地址的数据,而此时,对象B再来访问内存地址里的数据,必定会出现混乱(因为数据已经被删除了),这里我们想到,如果使用Java来测试,必然会抛出NullPointerException。
       Android的智能指针有三种,轻量级指针(LightRefBase通过简单的引用计数来维护对象的生命周期),强引用指针(使用了强引用计数技术),弱引用指针(弱引用计数技术)。

一 。 轻量级指针
         我们来看Android 系统源代码  system\core\include\utils\RefBase(Android 版本4.4以后的路径)

Read the fucking source code!   ----Linus

template < class T>
class LightRefBase
{
public :
    inline LightRefBase() : mCount(0) { }
    inline void incStrong(__attribute__((unused)) const void * id) const {
        android_atomic_inc(&mCount); //mCount+1  内部使用了线程互斥机制
    }
    inline void decStrong(__attribute__((unused)) const void * id) const {
        if (android_atomic_dec(&mCount) == 1) {  //mCount-1  线程互斥机制,返回在减1前的值
            delete static_cast < const T*>( this );   //如果没有指针指向这个地址,删除
     /*
        static_cast 用于向上转型 将this 转换成 T*
      */
        }
    }
    //! 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 renameRefs(size_t n, const ReferenceRenamer& renamer) { }
    inline static void renameRefId(T* ref,
            const void * old_id, const void * new_id) { }

private :
/*
当要求使用 volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据 因为该变量可能在多线程中访问(我们的操作系统中把它称为临界资源),所以要求每次都要去重新读取,当然单一使用这个修饰符是不足 以实现线程同步,所以还是要配合mutex来实现。
mutable  是用来消除变量的const  修饰,为撒要用这个来修饰呢?
原因是:在函数  inline void incStrong() const{...},函数被const修饰,是不允许在函数内存修改类的任何属性的,但是在函数的实现中又对mCount进行了加1操作,所以冲突了,故用mutable来去掉const的修饰(PS:既然要修改mCount的值,为什么Google工程师还要用const来修饰函数呢?)
* /
    mutable volatile int32_t mCount;
};

分析:
通过代码我们可以看到,轻引用只是维护了一个int变量mCount  (int32_t是一个结构体,是通过不同系统来定义一个32位的整数,因为Int在不同的硬件系统中所占用的长度不一定是32位),而该类是一个模板类(联想到Java的泛型类),在使用该类时,需要指明该类中的T到底是什么类型。该类主要是实现了一个计数器的功能,如果需要实现轻量级引用计数功能,还需要其他类来辅助。sp这个类实现了轻引用计数和强引用计数功能,这里我们暂时来分析轻引用计数的实现。


SP 实现在\system\core\include\utils\StrongPoint
//注解①
#define COMPARE (_op_)                                           \
inline bool operator _op_ ( const sp<T>& o) const {              \
    return m_ptr _op_ o.m_ptr;                                  \
}                                                               \
inline bool operator _op_ ( const T* o) const {                  \
    return m_ptr _op_ o;                                        \
}                                                               \
template < typename U>                                            \
inline bool operator _op_ ( const sp<U>& o) const {              \
    return m_ptr _op_ o.m_ptr;                                  \
}                                                               \
template < typename U>                                            \
inline bool operator _op_ ( const U* o) const {                  \
    return m_ptr _op_ o;                                        \
}                                                               \
inline bool operator _op_ ( const wp<T>& o) const {              \
    return m_ptr _op_ o.m_ptr;                                  \
}                                                               \
template < typename U>                                            \
inline bool operator _op_ ( const wp<U>& o) const {              \
    return m_ptr _op_ o.m_ptr;                                  \
}

// ---------------------------------------------------------------------------

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

#undef COMPARE

// ---------------------------------------------------------------------------
// No user serviceable parts below here.

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

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

template < typename T >
sp < T >& sp < T >::operator =( const sp < T >& other ) {
    T * otherPtr( other .m_ptr);
    if (otherPtr)
        otherPtr->incStrong( this );
    if (m_ptr)
        m_ptr->decStrong( this );
    m_ptr = otherPtr;
    return * this ;
}

template < typename T >
sp < T >& sp < T >::operator =( T * other ) {
    if ( other )
        other ->incStrong( this );
    if (m_ptr)
        m_ptr->decStrong( this );
    m_ptr = other ;
    return * this ;
}

template < typename T > template < typename U >
sp < T >& sp < T >:: operator =( const sp < U >& other) {
    T* otherPtr(other.m_ptr);
    if (otherPtr)
        otherPtr->incStrong( this );
    if (m_ptr)
        m_ptr->decStrong( this );
    m_ptr = otherPtr;
    return * this ;
}

template < typename T > template < typename U >
sp < T >& sp < T >::operator =( U * other ) {
    if ( other )
        (( T *) other )->incStrong( this );
    if (m_ptr)
        m_ptr->decStrong( this );
    m_ptr = other ;
    return * this ;
}

template < typename T >
void sp < T >::force_set( T * other) {
    other->forceIncStrong( this );
    m_ptr = other;
}

template < typename T >
void sp < T >::clear() {
    if (m_ptr) {
        m_ptr->decStrong( this );
        m_ptr = 0;
    }
}

template < typename T >
void sp < T >::set_pointer( T * ptr) {
    m_ptr = ptr;
}

分析:
注解①  : 这里是一系列的宏函数定义,主要是实现一系列的运算符重载(除了 = ) 这里的 = 有特殊的含义(两者间进行辅赋值的时候调用),这里帮大家复习一下:
假如A是一个类; A* a = new A();     A* b = a; //调用拷贝构造函数  A* c ;  c = a;    // =运算符重载

注解② :这里包含4个构造函数(两个普通的构造函数,两个拷贝构造函数),这里我们来分析一组普通的构造函数
sp( T* other); 和   template < typename U > sp( U * other);两者的区别在于后者是一个模板函数,由于两者都是
构造函数,那必然有个优先级,这里当然是前一个构造函数运行优先级高,因其确定。而为啥要提供一个模板构造函数来重载前一个构造函数呢,原因是我们可能传过来的可能不是T这个类型,而是另一种类型U(他的兄弟类,我自己的叫法)

注解 ③ :  =  运算符的重载,为什么要专门进行 = 运算符的重载呢?因为 A* a = new A();   A* c ;  c = a; 这时就有俩个指针同时指向new A()这个地址,引用计数为2,所以我们将在构造函数中将引用计数mCount设置为1,再进行拷贝构造函数,或者调用 c = a;时对引用计数进行加1 ,什么时候减1呢?当然是在析构函数中

注解 ④  : 运算符重载,让使用这个类如同使用指针一样

注解  : 调用宏函数来直接替换

注解⑥  :  T*  实际指向一个实际类型的变量

该类的主要作用是:
在调用该类的构造函数的时候,会传过来一个实际对象,此时,就会把该实际对象赋给m_ptr这个变量存起来,如果以后再调用该类对象的拷贝构造函数,或者=运算符重载函数时,那么实际调用的是m_ptr的函数来进行引用加1,这就是我们在使用轻量级计数时要继承LightRefBase这个类,因为我们需要调用它的方法,如果我们不继承,那么就无法调用到操作引用计数器的函数。

说了这么多,来教大家如何使用:
使用时有两个前提:
1)需要引用计数的类继承LightRefBase
2)为该类提供一个virtual 的析构函数
#define DEBUG 1
#define PRINT_DEBUG ()                      \
      if ( DEBUG )                             \
     cout<< "current line = " << __LINE__ <<endl  
//这个宏函数是我写来调试代码执行到哪里 
class NN : public LightRefBase < NN >{  // LightRefBase < NN > 记得添加模板,因为这是一个模板类
  public :
      NN(){ PRINT_DEBUG ();}
      virtual ~NN(){ PRINT_DEBUG ();}
 };

int main( int argc , char ** argv ){
      /*
     sp<NN>* nn = new sp<NN>(new NN());
     cout<<    nn->get()->getStrongCount();
     这样做也是可以的
     */
      NN * n = new NN ();  //引用计数初始化为0
      sp < NN > nn = n;  //引用计数加1
     cout<< "Light Ref count = " <<n->getStrongCount()<<endl;//  输出1
     {
           sp < NN > inner = nn;    //引用计数加1
           sp < NN > inner2 = nn;  //引用计数加1
          cout<< "Light Ref count = " <<n->getStrongCount()<<endl;    //输出3
     }
     //因为inner 和 inner2只在{}有效,出了“}”就会被释放掉(这里是对象不是指针,不然是不会自动释放的),所以减2
     cout<< "Light Ref count = " <<n->getStrongCount()<<endl;   //输出1
     getchar();
      return 0;
}

运行结果:


结语:
来至绵阳师范学院 (招生代码: 5123, 绵阳师范学院欢迎您)信息工程学院13级4班李超(学习andorid 一年半,有意招聘请发送邮件至:857713709@qq.com)。
下一节将分析强引用和弱引用的实现机制     3Q  :)

时间:2016/4/15

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值