本文是学习罗升阳大佬的《安卓系统源码与情景分析》的笔记和内容
一、为什么要用智能指针?
二、什么是智能指针?怎么用?
三、安卓系统三种智能指针的原理和关系
四、强弱指针的易混淆问题
一、为什么要用智能指针?
首先framework层的有些代码是用C++写的,C++最容易出错的地方是指针,如果忘记释放指针指向的对象的内存或者使用无效指针等,容易造成内存泄露、系统崩溃等问题。
那怎么办呢?
可以通过计数技术来维护一个对象的生命周期。也就是有新指针指向这个对象的时候,这对象的引用计数就加1,反之,每当有一个指针不再指向这个对象时,这个对象的引用计数就减1。这样当对象的引用计数为0的时候,就可以安全释放这个对象的内存。
但是让我们开发人员每次都在它引用计数为0手动释放内存,太麻烦,有没有自动释放内存的方法?
可以通过智能指针来做。
二、什么是智能指针?怎么用?
智能指针其实就是一种类,这种类在它自己的构造函数和析构函数中可以自动加减某个对象的引用计数
为什么这么说?
首先我们知道我们创建的类里面一般是没有什么引用计数这类东西的,所以
第一步,我们可以创建一个基类,这个基类里面有引用计数还有加减引用计数的方法
第二步,让我们的类继承这个base基类就可以使用引用计数和加减引用计数的方法了
如下:
//第一步:要有这么个基类里面有引用计数和加减引用计数的方法
class Base{
int count;//引用计数
void incCount(){
count ++;//每有新指针指向的时候自加1
}
void decCount(){
count --;//指针不再指向的时候自减1
}
}
//第二步,我自己的类去继承Base
class MyClass extends Base{
}
然后怎么让引用计数实现自动加减?
我们知道生成一个类的对象的时候系统会自动调用这个类的构造函数,释放这个类的对象的时候系统会自动调用这个类的析构函数,思路就来了,我们可以在构造函数和析构函数中实现引用计数的加减,所以
第三步,可以创建一个模板类(这个模板类就是智能指针,也呼应了我们前面说的“智能指针其实就是一种类,这种类在它自己的构造函数和析构函数中可以自动加减某个对象的引用计数”)。在模板类的构造函数中调用传进去的对象指针的增引用计数方法使得对象的引用计数+1,在模板类的析构函数中调用传进去的对象指针的减引用计数方法使得对象引用计数-1,当然这个对象的类必须是继承了基类Base的,如下:
//第三步,新建模板类
template <typename T>
class sp{
public :
template<typename U>sp(U * other);//构造函数
~sp();//析构函数
}
template <typename T>
sp<T>::sp(T* other)
{
if(other) other->incCount(this);
}
template <typename T>
sp<T>::~sp()
{
if(other) other->decCount(this);
}
第四步,生成需要控制的类的对象的指针,并让使用智能指针指向它
//第四步,生成需要控制的类的对象的指针,并让智能指针指向它
int main()
{
MyClass * myClass =new MyClass();
//这样会调用sp的构造函数实现myclass的引用计数加1,
//我的写法是sp<Myclass> pointer (myClass);更易理解
sp<MyClass> pointer= myClass;
return 0;//这会调用sp的析构函数实现myclass的引用计数减1
}
以上是智能指针定义和使用方法的简单分析
三、安卓系统三种智能指针的定义和关系
其实在安卓系统已经给好基类、模板类了,我们要做的就是第二和第四步,所以分析基类和模板类,就可以知道这三种智能智能指针的原理,我们就能知道怎么用它们。
那它们的基类和模板是什么样子的?
根据智能指针的不同,它们的基类和模板类有以下区别:
基类 | 模板类 | |
轻量级指针 | LightRefBase | sp |
强指针 | RefBase | sp |
弱指针 | RefBase | wp |
其中轻量级指针的原理就像前面第二部分说的原理一样。
强指针和弱指针是结合在一起使用的,它们有共同的基类RefBase,只是它们的模板类不同。
所以需要分析RefBase、sp、wp。分析侧重点如下:
RefBase:要搞清楚它的结构
sp:要搞清楚它的构造和析构函数。但是构造函数只是对强引用数和弱引用数简单加1,很简单。析构函数涉及到对象的生命周期控制方式和内存的释放,重点
wp:要搞清楚它的构造函数、析构函数和弱指针升级为强指针函数。但是构造函数只是对强引用数和弱引用数简单加1。析构函数和sp的差不多。重点是弱指针升级为强指针函数
下面侧重分析:
1、 RefBase类的结构
2、sp的析构函数
3、wp的弱指针升级为强指针函数
4、三者之间的关系
注意:
三种生命周期:默认为0,只受强指针引用数控制;1 受强指针和弱指针引用数同时控制;2 不受强弱指针引用数控制,相当于普通c++指针,需要手动释放内存;这个生命周期的控制符可以在我们创建自己的类的时候进行设置,比如:
四、强弱指针的易混淆问题
1、为什么弱指针要转化为强指针才能使用它指向的对象?
因为我们知道一个对象的生命周期如果只受强引用数控制的话,那么强引用数为0了,它就可以释放了,但是它还被弱指针引用着,弱指针如果想用你,你都释放了那还用啥,所以需要判断你有没有释放,这就可以通过弱指针的attemptIncStrong来做,里面做了很多判断处理,具体可看第三部分的第3点wp的弱指针升级为强指针函数。那我只判断释放不释放,我不转强指针不行吗?不行,这是规定
2、只受强引用数控制的生命周期的类,强指针中如果把对象释放了,它里面的计数对象impl还被弱指针引用着,怎么办?
还被弱引用着话就不能把impl释放,那什么时候释放?,弱指针引用数不为0,说明还有弱指针指向它,到时候弱指针执行析构函数的时候会释放它