Android的轻量级指针原理与使用

Android系统提供了三种类型的c++智能指针,分别为轻量级指针(Light Pointer)、强指针(Strong Pointer)、弱指针(Weak Pointer)。其中,轻量级指针使用了简单的引用计数,而强指针和弱指针分别使用了强引用计数和弱引用计数。现在分析的是Android的轻量级指针的实现与简单应用。


一、LightRefBase类

如果一个类的对象支持使用轻量级指针,那么这个类在定义时必须继承LightRefBase类。LightRefBase类提供了一个简单的引用计数器,它的定义如下:

代码目录:framework/base/include/utils/RefBase.h

template <class T>
class LightRefBase
{
public:
    inline LightRefBase() : mCount(0) { }
    inline void incStrong(__attribute__((unused)) const void* id) const {
        android_atomic_inc(&mCount); /*原子操作,不可被其他线程打断*/
    }
    inline void decStrong(__attribute__((unused)) const void* id) const {
        if (android_atomic_dec(&mCount) == 1) /*原子操作,不可被其他线程打断*/ {
            delete static_cast<const T*>(this); /*计数值为0,表示可以释放对象内存了*/
        }
    }
    //! DEBUGGING ONLY: Get current strong ref count.
    inline int32_t getStrongCount() const {
        return mCount;
    }

protected:
    inline ~LightRefBase() { }

private:
    mutable volatile int32_t mCount; /*对象的引用计数值*/
};

二、sp类

sp类在源代码中既是轻量级指针的实现类,也是强指针的实现类。这里只关注轻量级指针相关的代码:
代码目录:framework/base/include/utils/StrongPointer.h

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; /*成员变量:模板指针*/
};

 

再来看看两个构造函数的具体实现:

template<typename T>
sp<T>::sp(T* other)
        : m_ptr(other) /*普通构造函数:初始化成员变量m_ptr*/ {
    if (other)
        other->incStrong(this); /*增加引用计数*/
}

template<typename T>
sp<T>::sp(const sp<T>& other)
        : m_ptr(other.m_ptr) /*拷贝构造函数:初始化成员变量m_ptr*/ {
    if (m_ptr)
        m_ptr->incStrong(this); /*增加引用计数*/
}

析构函数的实现:

template<typename T>
sp<T>::~sp() {
    if (m_ptr)
        m_ptr->decStrong(this); /*减少引用计数*/
}


二、简单应用

定义一个普通的Person类:

class Person {
private:
	char *name ;
	
public:	
	Person() {
		cout<<"Person()"<<endl ;
	}

	~Person() {
		cout<<"~Person()"<<endl ;
	}

	void printInfo(void){
		cout<<"just for test !"<<endl ;
	}
} ;

在这个普通的Person类中,我们仅仅定义了几个普通的成员变量和普通的成员函数。这时该如何使这个类具有轻量级指针的功能呢?

1、要使这个类具有引用计数器,它在定义时必须继承LightRefBase这个模板类;

2、在使用时,先new 一个Person类,并创建一个轻量级指针来引用它;

3、接下来就可以操作Person类的成员函数了。

由于代码中用到了LightRefBase类、sp类,这两个类的定义与实现分别在RefBase.h 、StrongPointer.h ,而这两个文件在Android系统中是以库文件的形式存在的。它们位置在Android源码目录 system/core/include/utils 和 system/core/include/cutils目录下。因此,我们将这两个目录拷贝到当前应用程序目录的include目录下面。当前Person.cpp代码如下:

#include<iostream>
#include <utils/RefBase.h> /*包含RefBase.h文件,该文件中包含了StrongPointer.h,因此不必重复包含*/

using namespace std;
using namespace android; /*使用android命名空间*/

class Person : public LightRefBase<Person> /*要使这个类具有引用计数器,它在定义时必须继承LightRefBase这个模板类*/{
private:
	char *name ;
	
public:	
	Person() {
		cout<<"Person()"<<endl ;
	}

	~Person() {
		cout<<"~Person()"<<endl ;
	}

	void printInfo(void){
		cout<<"just for test !"<<endl ;
	}
} ;


int main(int argc , char** argv)
{
	/*使用轻量级指针*/
	sp<Person> lp = new Person() ; /*普通构造*/
	sp<Person> lp2 = lp ;	    /*拷贝构造*/
	/*使用轻量级指针重载的运算符*/	
	lp->printInfo() ;
	(*lp).printInfo() ;
	
	lp2->printInfo() ;
	(*lp2).printInfo() ;
	
	return 0 ;
}

接下来在PC机上编译该Person.cpp : g++ -o Person Person.cpp -I include

发现如下错误:

在incStrong 和decStrong过程中的原子操作未定义。原因在于Android系统默认采用arm架构中的原子操作,而PC机采用x86架构,因此解决方法在RefBase.h 、StrongPointer.h 中将 #include <cutils/atomic.h> 改为 #include <cutils/atomic-x86.h> ,重新编译即可运行:

可以看到,析构函数正常执行,满足我们的预期。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值