Android系统提供了三种类型的C++智能指针,分别为轻量级指针(light pointer),强指针(strong pointer)和弱指针(weak pointer)
__attribute__((unused)):该属性定义的函数或变量可能不使用 告诉编译器不要产生警告信息在编译的时候
C++风格的类型转换提供了4种类型转换操作符来应对不同场合的应用。
const_cast,字面上理解就是去const属性。
static_cast,命名上理解是静态类型转换。如int转换成char。
dynamic_cast,命名上理解是动态类型转换。如子类和父类之间的多态类型转换。
reinterpreter_cast,仅仅重新解释类型,但没有进行二进制的转换。
去const属性用const_cast。
基本类型转换用static_cast。
多态类之间的类型转换用daynamic_cast。
不同类型的指针类型转换用reinterpreter_cast
typedef typename std::vector<T>::size_type size_type;
语句的真是面目是:
typedef创建了存在类型的别名,而typename告诉编译器std::vector<T>::size_type是一个类型而不是一个成员。
按 C++ 标准来说,template<typename T>
template<class T> 用于类,T 可以取任何类。
轻量级指针
C++与JAVA的区别是内存需要手动管理,具体的来说就是由NEW分配的内存或对像需要手动调用delete来手动删除。这样就导致一个问题,如果大型软件中一个对像可能在多个线程中有使用,必须出现重复多次引用的情况。那么我们应该在那个线程去释放了,这样就可能导致释放了但还有的线程在使用导致内存泄露,还有可能导航野指针,既不使用了反而没有释放的情况.针对这种问题我们可以想到应该由C++类的析构函数来解决,就是在程序的最后会自动调用析构函数,我们在析构函数中来释放类对像。针对多次引用想像应该可以引入计数机制,当在调用析构函数时要判断引用当前对像的个数。如果当前对蚥引用次数为0了当然可以释放了。如果不为0就不应该释放。针对这种解决问题的办法我叫做轻量级指针。
但这种解决办法也有一个瓶颈既有的情况解决不了对像释放,这种情况我们由对像A和对像的相互引用来说明。A对像引用了B对像,B对像也引用了A对像。
对于这种情况我们引入的强指针和弱指针来解决,这是另一个分析主题
用到一个通用的类LightRefBase 和sp(sp在强指针和弱指针中也有用但这儿我们只分析与轻量级指针有关的部分),轻量级指针来管理的指针是由这两个类来配合清晰的知道对像的调用次数的才能智能的处理。如果像AB那样没有按固定的调用模式的话也是处理不了的
LightRefBase 是一个引用数用的通用类,任何我们需要智能管理指针的对像都要寄存它。它实现了一个变量数和几个函数用于管理类对像的。
template <class T>
class LightRefBase{
public:
inline LightRefBase():mCount(0){}//引用计算器为0初始化
inline void incStrong(const void* id) const{
android_atomic_inc(&mCount);//引用计算数器加1
}
inline void decStrong(const void* id) const{
if(android_atomic_dec(&mCount)==1){//引用计算器减1 如果读出来的数本身就是1了 减一之后就应该释放了
delete static_cast<const T*>this;//释放对像。这个对像是指我们要跟踪的对像既寄存了lightrefbase类的类对像。
}
}
inline int32_t getStrongCount() const{
return mCount;//取得当前引用计数器值
}
private:
mutable volatile int32_t mCount;//对用计算器
}
Sp类是用于引用我们自定义的类对像。SP不应该由NEW直接分配。我们这儿利用的就是C++程序最后自动调用析构的原理。如果用了NEW自动调不了析构我们就没办法去调用自定义的类对像了。因此SP只能是类对像的引用或指针。既在程序的最后必须要能自动调到SP的析构函数就行了。
template <typename T>//T是我们自定义的寄存了ligthrefbase的类
class sp{
public:
inline sp():m_ptr(0){}//初始化为0
sp(T* other);//指针拷贝构造函数 通过这个函数之后T中的引用计算器加1
sp(const sp<T>& other);;//引用拷贝构造函数 通过这个函数之后T中的引用计算器加1
~sp();//析构函数 T中的对像计数器减1 如果已经为1了那么T对像应该释放了。
private:
T* m_ptr;
}
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>
sp<T>::~sp()
{
if(m_ptr)m_ptr->decStrong(this);
}
下面一个实例来分析轻量级智能智指针的实现原理的。
#include<stdio.h>
#include<utils/RefBase.h>
using namespace android;
class LightClass:public LightRefBase<LightClass>{
public:
LightClass(){
printf("Construct LightClass Object.");
}
virtual ~LightClass(){
printf("Destroy LightClass Object.");
}
}
int main(int argc,char **argv){
LightClass *pLightClass = new LightClass();//分配对像
sp<LightClass> lpOut = pLightClass;//调用sp(T* other);函数来把pLightClass 的次数引用加1
printf("Ligth Ref Count:%d.\n",pLightClass->getStrongCount());
{ sp<LightClass> lpInner = lpOut;//sp(const sp<T>& other)调用这个数pLightClass中的引用次数加1,
printf("Light Ref Count:%d.\n",pLightClass->getStrongCount());
}
printf("Light Ref Count:%d.\n",pLightClass->getStrongCount());
}
通过上分析可能在后面的使用中我们要使用lpInner lpOut 来操作我们对像pLightClass,而不应该直接去pLightClass它。如果直接操作当时不知道用了多少次不便于管理 。通过lpInner lpOut来操作它就可以知道调用了多少。进一步到最后可以准确的释放