智能指针
使用引用计数的方法,每当有一个指针指向了一个new出来的对象时,就对这个对象的引用计数增加1,每当有一个指针不再使用这个对象时,就对这个对象的引用计数减少1,每次减1之后,如果发现引用计数值为0时,那么,就要delete这个对象了,这样就避免了忘记delete对象或者这个对象被delete之后其它地方还在使用的问题了,因此我们引入轻量级指针。
轻量级指针
轻量级指针基类的定义如下:
template<class T>
classLightRefBase
{
public:
inlineLightRefBase() : mCount(0) { }
inlinevoid incStrong(const void* id) const {
android_atomic_inc(&mCount);
}
inlinevoid decStrong(const void* id) const {
if(android_atomic_dec(&mCount) == 1) {
deletestatic_cast<const T*>(this);
}
}
//!DEBUGGING ONLY: Get current strong ref count.
inlineint32_t getStrongCount() const {
returnmCount;
}
protected:
inline~LightRefBase() { }
private:
mutablevolatile int32_t mCount;
};
该类有一个成员变量mCount,这就是引用计数器了,它的初始化值为0,另外,这个类还提供两个成员函数incStrong和decStrong来维护引用计数器的值,这两个函数就是提供给智能指针来调用的了,这里要注意的是,在decStrong函数中,如果当前引用计数值为1,那么当减1后就会变成0,于是就会delete这个对象。
template<typename T>
classsp
{
public:
typedeftypename RefBase::weakref_type weakref_type;
······
T* m_ptr;
};
构造函数
template<typenameT>
sp<T>::sp(T*other)
:m_ptr(other)
{
if(other) other->incStrong(this);
}
template<typenameT>
sp<T>::sp(constsp<T>& other)
:m_ptr(other.m_ptr)
{
if(m_ptr) m_ptr->incStrong(this);
}
析构函数
template<typenameT>
sp<T>::~sp()
{
if(m_ptr) m_ptr->decStrong(this);
}
classLightClass : public LightRefBase<LightClass>
{
······
}
intmain(int argc, char** argv)
{
LightClass*pLightClass = new LightClass();
sp<LightClass>lpOut = pLightClass;
printf("LightRef Count: %d.\n", pLightClass->getStrongCount());Ⅰ
{
sp<LightClass>lpInner = lpOut;
printf("LightRef Count: %d.\n", pLightClass->getStrongCount());Ⅱ
}
printf("LightRef Count: %d.\n", pLightClass->getStrongCount());Ⅲ
return0;
}
Ⅰ获得的值为1
Ⅱ获得的值为2
Ⅲ获得的值为1
当main()函数执行完后,智能指针lpOut也会被析构,被析构时,它会再次减少当前对象的引用计数,这时候,对象的引用计数值就为0了,于是,它就会被delete了。
系统中有两个对象A和B,在对象A的内部引用了对象B,而在对象B的内部也引用了对象A。当两个对象A和B都不再使用时,垃圾收集系统会发现无法回收这两个对象的所占据的内存的,因为系统一次只能收集一个对象,而无论系统决定要收回对象A还是要收回对象B时,都会发现这个对象被其它的对象所引用,因而就都回收不了,这样就造成了内存泄漏,因此我们引入强弱指针。
强弱指针
Android中定义了两种智能指针类型,一种是强指针sp(strongpointer),一种是弱指针(weakpointer)。
弱指针也指向一个对象,但是弱指针仅仅记录该对象的地址,不能通过弱指针来访问该对象,也就是说不能通过弱指针来调用对象的成员函数或访问对象的成员变量。要想访问弱指针所指向的对象,需首先将弱指针升级为强指针(通过wp类所提供的promote()方法)。弱指针所指向的对象是有可能在其它地方被销毁的,如果对象已经被销毁,wp的promote()方法将返回空指针,这样就能避免出现地址访问错的情况。
强弱指针的基类定义如下:
classRefBase
{
public:
void incStrong(const void* id) const;
void decStrong(const void* id) const;
void forceIncStrong(const void* id) const;
int32_t getStrongCount() const;
classweakref_type
{
public:
RefBase* refBase() const;
void incWeak(const void* id);
void decWeak(const void* id);
bool attemptIncStrong(const void* id);
bool attemptIncWeak(const void* id);
int32_t getWeakCount() const;
void printRefs() const;
void trackMe(bool enable, bool retain);
};
······
protected:
RefBase();
virtual ~RefBase();
enum{
OBJECT_LIFETIME_WEAK = 0x0001,
OBJECT_LIFETIME_FOREVER= 0x0003
};
virtualvoid onFirstRef();
virtualvoid onLastStrongRef(const void* id);
virtualbool onIncStrongAttempted(uint32_t flags, const void* id);
virtualvoid onLastWeakRef(const void* id);
private:
friendclass weakref_type;
classweakref_impl;
RefBase(constRefBase& o);
RefBase& operator=(const RefBase& o);
weakref_impl*const mRefs;
};
Weakref_impl的定义如下:
classRefBase::weakref_impl : public RefBase::weakref_type
{
public:
volatileint32_t mStrong;
volatileint32_t mWeak;
RefBase*const mBase;
volatileint32_t mFlags;
weakref_impl(RefBase*base)
:mStrong(INITIAL_STRONG_VALUE)
,mWeak(0)
,mBase(base)
,mFlags(0)
{
}
voidaddStrongRef(const void* /*id*/) { }
voidremoveStrongRef(const void* /*id*/) { }
voidaddWeakRef(const void* /*id*/) { }
voidremoveWeakRef(const void* /*id*/) { }
voidprintRefs() const { }
voidtrackMe(bool, bool) { }
}
强指针:
classsp
{
public:
typedeftypename RefBase::weakref_type weakref_type;
sp(T*other);
sp(constsp<T>& other);
template<typenameU> sp(U* other);
template<typenameU> sp(const sp<U>& other);
~sp();
······
}
类中变量:mStrong和mWeak分别表示对象的强引用计数和弱引用计数;
mFlags是一个标志位,它指示了维护对象引用计数所使用的策略;
sp<T>::sp(T*other)
:m_ptr(other)
{
if(other) other->incStrong(this);
}
incStrong增加强引用计数同时,增加弱引用计数。
sp<T>::~sp()
{
if(m_ptr) m_ptr->decStrong(this);
}
decStrong减少强引用计数,如果强引用计数在减少前值为1,判断对象的生命周期是否受强引用控制,如果受强引用控制,则释放该对象。同时减少弱引用计数,如果弱引用计数在减少前值为1,判读对象的生命周期是否受弱引用控制,如果受弱引用控制,则释放该对象。
最后我们分析总结如下:
1mFlags = 0时即对象的标志位被设置为0,那么只要发现对象的强引用计数值为0,那就会自动delete掉这个对象;
2mFlags =OBJECT_LIFETIME_WEAK即对象的标志位被设置为OBJECT_LIFETIME_WEAK,那么只有当对象的强引用计数和弱引用计数都为0的时候,才会自动delete掉这个对象;
3mFlags =OBJECT_LIFETIME_FOREVER即对象的标志位被设置为OBJECT_LIFETIME_FOREVER,那么对象就永远不会自动被delete掉,谁new出来的对象谁来delete掉。
弱指针:
classwp
{
public:
typedeftypename RefBase::weakref_type weakref_type;
inlinewp() : m_ptr(0) { }
wp(T*other);
wp(constwp<T>& other);
wp(constsp<T>& other);
template<typenameU> wp(U* other);
template<typenameU> wp(const sp<U>& other);
template<typenameU> wp(const wp<U>& other);
~wp();
sp<T>promote() const;
······
}
wp<T>::wp(T*other)
:m_ptr(other)
{
if(other) m_refs = other->createWeak(this);
}
RefBase::weakref_type*RefBase::createWeak(const void* id) const
{
mRefs->incWeak(id);
returnmRefs;
}
createWeak函数调用了incWeak增加实际引用对象的弱引用计数。
wp<T>::~wp()
{
if(m_ptr) m_refs->decWeak(this);
}
decWeak减少实际引用对象的弱引用计数。
sp<T>wp<T>::promote() const
{
returnsp<T>(m_ptr, m_refs);
}
Promote将弱指针升级为强指针。
弱指针与强指针的区别:弱指针不可以直接操作它所引用的对象,因为它所引用的对象可能不受弱引用计数控制的,即它所引用的对象可能是一个无效的对象。因此如果需要操作一个弱指针所引用的对象,那么就需要promote将这个弱指针升级为强指针,如果升级成功,就说明该弱指针所引用的对象还没有被销毁,可以正常使用。