Android中的智能指针
C/C++项目中常见的指针问题有三类:
- 指针没有初始化,或者新申请的内存块没有按照情况进行初始化。
- new/delete操作符没有匹配使用,忘记delete造成内存泄漏。
- 野指针。一个对象不知道有多少个指针引用它,当对象被在错误的时机销毁时,引用它的指针就变成了野指针。
为了解决上面三个问题,智能指针被发明了出来。
智能指针,简单来说就是通过引用计数法记录一个对象被引用的次数,当引用次数变为0时自动销毁该对象,而不需要程序员手动delete。
了解引用计数法的同学,应该知道相对于可达性分析法有一个循环引用(A引用B,B引用A)的弊端,循环引用则导致了某些对象的引用次数一直不为0,从而引起内存泄漏。为了解决这个问题,C/C++添加了弱引用的概念。
下面我们逐步分析智能指针的实现原理。
自动初始化和销毁
假设定义了一个学生类:
class Student {
public:
Student() {
printf("new Student");
}
}
我们在使用这个类时,需要先new一个实例出来,使用结束后再手动delete。
Student stu = new Student();
...
//一些逻辑处理
...
//这里是否可以安全销毁stu实例?
delete stu;
上面这段代码的关键在于:经过复杂的逻辑处理后,stu实例可能被其他指针引用,导致最后无法确定是否可以安全的销毁原始指针stu。
下面通过智能指针类使用该类:
//仍然创建一个新实例
Student stu = new Student();
//以stu初始化一个sp(StrongPoint)实例
sp<Student> stuSp = new sp(stu);
...
//一些逻辑处理
...
//可以安全销毁智能指针实例
delete stuSp;
使用智能指针stuSp后,我们不必关心stu实例的销毁。只要我们不再使用stuSp实例后就主动销毁它,因为在sp内部保存了stu的指针并维护stu的引用计数,在sp的析构函数中会判断stu的引用数是否为0,如果为0就会销毁stu实例。
下面对sp的实现一探究竟:
//frameworks/rs/cpp/util/StrongPointer.h
//一个普通构造函数
//将传入的对象赋值给m_ptr变量,并调用其incStrong函数,增加其引用计数
template<typename T>
sp<T>::sp(T* other) : m_ptr(other)
{
if (other) other->incStrong(this);
}
//析构函数
//调用m_ptr对象的decStrong函数,减少引用计数。
//decStrong函数内部会判断计数为0时,就会销毁该对象
template<typename T>
sp<T>::~sp()
{
if (m_ptr) m_ptr->decStrong(this);
}
//提供了三种获取原始指针的方式:星号、右箭头、get()函数
//也就是说我可以像使用原始指针那样使用使用强指针:stuSp* 等价于 stu*
inline T& operator* () const { re