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> ,重新编译即可运行:
可以看到,析构函数正常执行,满足我们的预期。