一 RefBase类介绍
RefBase提供了引用计数器的功能,所有接受sp、wp管理的类都需要继承RefBase。RefBase类定义了一个内部接口类weakref_type,它提供了操作弱引用计数的一系列接口,具体的实现位于weakref_impl类中。RefBase持有weakref_impl*类型的指针成员mRefs,通过mRefs实现对强、弱引用的计数管理。
class RefBase
{
public:
void incStrong(const void* id) const;
void decStrong(const void* id) const;
void forceIncStrong(const void* id) const;
//! DEBUGGING ONLY: Get current strong ref count.
int32_t getStrongCount() const;
class weakref_type
{
public:
RefBase* refBase() const;
void incWeak(const void* id);
void decWeak(const void* id);
bool attemptIncStrong(const void* id);
};
weakref_type* createWeak(const void* id) const;
weakref_type* getWeakRefs() const;
protected:
RefBase();
virtual ~RefBase();
//! Flags for extendObjectLifetime()
enum {
OBJECT_LIFETIME_WEAK = 0x0001,
OBJECT_LIFETIME_FOREVER = 0x0003
};
void extendObjectLifetime(int32_t mode);
//! Flags for onIncStrongAttempted()
enum {
FIRST_INC_STRONG = 0x0001
};
virtual void onFirstRef();
virtual void onLastStrongRef(const void* id);
virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
virtual void onLastWeakRef(const void* id);
private:
friend class weakref_type;
class weakref_impl;
RefBase(const RefBase& o);
RefBase& operator=(const RefBase& o);
weakref_impl* const mRefs;//管理强、弱引用计数值
};
1. RefBase的构造函数:
RefBase::RefBase()
: mRefs(new weakref_impl(this))
{
}
RefBase在构造函数中创建了weakref_impl类型的对象,以初始化mRefs。
class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
volatile int32_t mStrong;
volatile int32_t mWeak;
RefBase* const mBase;
volatile int32_t mFlags;
#if !DEBUG_REFS
weakref_impl(RefBase* base)
: mStrong(INITIAL_STRONG_VALUE)
, mWeak(0)
, mBase(base)
, mFlags(0)
{
}
void addStrongRef(const void* /*id*/) { }
void removeStrongRef(const void* /*id*/) { }
void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { }
void addWeakRef(const void* /*id*/) { }
void removeWeakRef(const void* /*id*/) { }
void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { }
void printRefs() const { }
void trackMe(bool, bool) { }
#else
...
}
可见,构造函数中mStrong为INITIAL_STRONG_VALUE,mWeak为0。
2. RefBase的析构函数
C++中析构函数中务必注意的是申请资源的释放,这里要考虑释放mRef对象。
RefBase::~RefBase()
{
if (mRefs->mStrong == INITIAL_STRONG_VALUE) {
// we never acquired a strong (and/or weak) reference on this object.
delete mRefs;
} else {
// life-time of this object is extended to WEAK or FOREVER, in
// which case weakref_impl doesn't out-live the object and we
// can free it now.
if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
// It's possible that the weak count is not 0 if the object
// re-acquired a weak reference in its destructor
if (mRefs->mWeak == 0) {
delete mRefs;
}
}
}
// for debugging purposes, clear this.
const_cast<weakref_impl*&>(mRefs) = NULL;
}
二 强指针sp
sp对泛型T*类型指针进行了封装,而T就是RefBase或其子类,因此sp或wp就是管理RefBase系列的指针的。
template <typename T>
class sp
{
public:
typedef typename RefBase::weakref_type weakref_type;
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; }
// Operator
COMPARE(==)
COMPARE(!=)
COMPARE(>)
COMPARE(<)
COMPARE(<=)
COMPARE(>=)
private:
template<typename Y> friend class sp;
template<typename Y> friend class wp;
// Optimization for wp::promote().
sp(T* p, weakref_type* refs);
T* m_ptr;//类型T必须是继承自RefBase。
};
2.1 sp的构造函数
- 强引用部分
调用mRefs->addStrongRef()函数,这个在Release版本中什么也不做;
将mRefs的mStrong加1。注意,mStrong表示被强引用的次数,第一次被引用时mStrong值为1,同时会调用RefBase类的onFirstRef()函数。 - 弱引用部分
调用mRefs->incWeak()函数,它包含了:
将mRefs的mWeak加1,mWeak表示被弱引用的次数;
调用mRefs的addWeakRef()函数,这个在Release版本中什么也不做。
2.2 sp的析构函数
- 强引用部分
调用mRefs的removeStrongRef(),这个在Release版本中为空;
将mRefs的mStrong减去1,若果是最后一次调用,则:
首先会调用onLastStrongRef(),默认实现为空,如果需要可以在子类中实现;然后,如果生命周期是受OBJECT_LIFETIME_STRONG控制,则delete当前RefBase对象(注意这里RefBase对象中的mRefs所指weak_impl对象还没有被释放掉,有内存泄露的风险)。
- 弱引用部分
调用decWeak(), 将mWeak减去1。如果是最后一次引用,则一定要考虑指针释放的问题,如下:
(1) 如果生命周期是受OBJECT_LIFETIME_STRONG控制,则
mStrong的值为INITIAL_STRONG_VALUE,表示根本没有创建过sp对象,直接delete RefBase对象,那它里面的mRef指针呢?答案是在RefBase的析构函数中,会判断如果mRefs->mStrong == INITIAL_STRONG_VALUE则delete mRefs。
mStrong的值不为INITIAL_STRONG_VALUE时,则delete掉 mRefs所指对象。
(2) 如果生命周期受OBJECT_LIFETIME_WEAK控制,因为这是最后一次弱引用,我们终于可以delete RefBase对象了,那它里面的mRef指针呢?答案是在RefBase的析构函数中,有这样的判断:
if((mRefs->mFlags&OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
// It's possible that the weak count is not 0 if the object
// re-acquired a weak reference in its destructor
if (mRefs->mWeak == 0) {
delete mRefs;
}
}
(3) 如果生命周期受OBJECT_LIFETIME_FOREVER控制,什么也不做。
三、 弱指针wp
3.1 wp的构造函数
只有sp中的弱引用部分
3.2 wp的析构函数
只有sp中的弱引用部分
四、弱指针升级为强指针
弱指针wp不能直接操作其封装的T*类型的对象,它没有重载*和->操作符;不过wp类提供了一个将当前的弱指针对象升级为强指针对象的函数promote()。
emplate <typename T>
class wp {
public:
// promotion to sp
sp<T> promote() const;
private:
T* m_ptr;
weakref_type* m_refs;
};
template<typename T>
sp<T> wp<T>::promote() const
{
return sp<T>(m_ptr, m_refs);
}
可见,升级的方式就是使用变量m_ptr和m_refs来构造一个强指针对象。
template<typename T>
sp<T>::sp(T* p, weakref_type* refs)
: m_ptr((p && refs->attemptIncStrong(this)) ? p : 0)
{
}
重点是attemptIncStrong()函数,返回true时即表示可以升级;否则m_ptr为0。具体的方法是:
判断m_refs所持有的mStrong值,用curCount表示,分以下3种情况:
(1) curCount > 0 && curCount != INITIAL_STRONG_VALUE
表示已经有强指针在引用T对象,所以只需把m_refs所持有的mWeak和mStrong都加1即可;
(2)curCount = INITIAL_STRONG_VALUE
表示对象T还没有被强指针引用过,分两种模式:
OBJECT_LIFETIME_WEAK:默认返回true,不过受限于RefBase::onIncStrongAttempted()的函数返回值(默认true);不过这个函数可以被RefBase的子类修改,如果被重写为返回false则表示设计者不希望升级;
OBJECT_LIFETIME_STRONG: 返回true;
(3)curCount <=0
表示对象T已经被销毁掉,正在尝试救活(revive)它,如果该对象确实有更长的生命周期(longer lifetime)的话是被允许的。
OBJECT_LIFETIME_WEAK:默认返回true,不过受限于RefBase::onIncStrongAttempted()的函数返回值(默认true);不过这个函数可以被RefBase的继承类修改,如果被重写为返回false则表示设计者不希望升级;
OBJECT_LIFETIME_STRONG: 返回false。
如果返回true,则将强、弱引用计数分别加1, 如果是第一次引用,会调用onFirstRef()。