前面已经说过了轻量级智能指针和强引用智能指针,今天来说一下最后一个弱引用智能指针。弱引用指针的概念其实和前面介绍的强引用关系是比较密切的,再了解了强引用的基础上再来看弱引用,这样逻辑上就可以比较通顺了。相对前2个智能指针而言,弱引用智能指针算是最复杂的一个(其实也还好,理解了强引用,其实也就比较容易理解弱引用了),下面我们就开始来介绍弱引用智能指针。
首先还是和前面一样,弱指针引用的对象也是要继承一个基类,这里和强引用指针一样,也是RefBase类,前面强引用已经介绍过,这里还是把这个类也贴出来看一下,省得在翻到前面去看了:
```c++
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);
//! This is only safe if you have set OBJECT_LIFETIME_FOREVER.
bool attemptIncWeak(const void* id);
//! DEBUGGING ONLY: Get current weak ref count.
int32_t getWeakCount() const;
//! DEBUGGING ONLY: Print references held on object.
void printRefs() const;
//! DEBUGGING ONLY: Enable tracking for this object.
// enable -- enable/disable tracking
// retain -- when tracking is enable, if true, then we save a stack trace
// for each reference and dereference; when retain == false, we
// match up references and dereferences and keep only the
// outstanding ones.
void trackMe(bool enable, bool retain);
};
weakref_type* createWeak(const void* id) const;
weakref_type* getWeakRefs() const;
//! DEBUGGING ONLY: Print references held on object.
inline void printRefs() const { getWeakRefs()->printRefs(); }
//! DEBUGGING ONLY: Enable tracking of object.
inline void trackMe(bool enable, bool retain)
{
getWeakRefs()->trackMe(enable, retain);
}
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;
};
```
同样这个基类里面,最关键的就是最后一个私有变量weakref_impl* const mRefs,这个变量weakref_impl类中,保存着引用计数器:
```c++
class RefBase::weakref_impl : public RefBase::weakref_type // 继承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 addWeakRef(const void* /*id*/) { }
void removeWeakRef(const void* /*id*/) { }
void printRefs() const { }
void trackMe(bool, bool) { }
#else
weakref_impl(RefBase* base)
: mStrong(INITIAL_STRONG_VALUE)
, mWeak(0)
, mBase(base)
, mFlags(0)
, mStrongRefs(NULL)
, mWeakRefs(NULL)
, mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
, mRetain(false)
{
//LOGI("NEW weakref_impl %p for RefBase %p", this, base);
}
~weakref_impl()
{
LOG_ALWAYS_FATAL_IF(!mRetain && mStrongRefs != NULL, "Strong references remain!");
LOG_ALWAYS_FATAL_IF(!mRetain && mWeakRefs != NULL, "Weak references remain!");
}
void addStrongRef(const void* id)
{
addRef(&mStrongRefs, id, mStrong);
}
void removeStrongRef(const void* id)
{
if (!mRetain)
removeRef(&mStrongRefs, id);
else
addRef(&mStrongRefs, id, -mStrong);
}
void addWeakRef(const void* id)
{
addRef(&mWeakRefs, id, mWeak);
}
void removeWeakRef(const void* id)
{
if (!mRetain)
removeRef(&mWeakRefs, id);
else
addRef(&mWeakRefs, id, -mWeak);
}
void trackMe(bool track, bool retain)
{
mTrackEnabled = track;
mRetain = retain;
}
void printRefs() const
{
String8 text;
{
AutoMutex _l(const_cast<weakref_impl*>(this)->mMutex);
char buf[128];
sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);
text.append(buf);
printRefsLocked(&text, mStrongRefs);
sprintf(buf, "Weak references on RefBase %p (weakref_type %p):\n", mBase, this);
text.append(buf);
printRefsLocked(&text, mWeakRefs);
}
{
char name[100];
snprintf(name, 100, "/data/%p.stack", this);
int rc = open(name, O_RDWR | O_CREAT | O_APPEND);
if (rc >= 0) {
write(rc, text.string(), text.length());
close(rc);
LOGD("STACK TRACE for %p saved in %s", this, name);
}
else LOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this,
name, strerror(errno));
}
}
private:
struct ref_entry
{
ref_entry* next;
const void* id;
#if DEBUG_REFS_CALLSTACK_ENABLED
CallStack stack;
#endif
int32_t ref;
};
void addRef(ref_entry** refs, const void* id, int32_t mRef)
{
if (mTrackEnabled) {
AutoMutex _l(mMutex);
ref_entry* ref = new ref_entry;
// Reference count at the time of the snapshot, but before the
// update. Positive value means we increment, negative--we
// decrement the reference count.
ref->ref = mRef;
ref->id = id;
#if DEBUG_REFS_CALLSTACK_ENABLED
ref->stack.update(2);
#endif
ref->next = *refs;
*refs = ref;
}
}
void removeRef(ref_entry** refs, const void* id)
{
if (mTrackEnabled) {
AutoMutex _l(mMutex);
ref_entry* ref = *refs;
while (ref != NULL) {
if (ref->id == id) {
*refs = ref->next;
delete ref;
return;
}
refs = &ref->next;
ref = *refs;
}
LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p (weakref_type %p) that doesn't exist!",
id, mBase, this);
}
}
void printRefsLocked(String8* out, const ref_entry* refs) const
{
char buf[128];
while (refs) {
char inc = refs->ref >= 0 ? '+' : '-';
sprintf(buf, "\t%c ID %p (ref %d):\n",
inc, refs->id, refs->ref);
out->append(buf);
#if DEBUG_REFS_CALLSTACK_ENABLED
out->append(refs->stack.toString("\t\t"));
#else
out->append("\t\t(call stacks disabled)");
#endif
refs = refs->next;
}
}
Mutex mMutex;
ref_entry* mStrongRefs;
ref_entry* mWeakRefs;
bool mTrackEnabled;
// Collect stack traces on addref and removeref, instead of deleting the stack references
// on removeref that match the address ones.
bool mRetain;
#if 0
void addRef(KeyedVector<const void*, int32_t>* refs, const void* id)
{
AutoMutex _l(mMutex);
ssize_t i = refs->indexOfKey(id);
if (i >= 0) {
++(refs->editValueAt(i));
} else {
i = refs->add(id, 1);
}
}
void removeRef(KeyedVector<const void*, int32_t>* refs, const void* id)
{
AutoMutex _l(mMutex);
ssize_t i = refs->indexOfKey(id);
LOG_ALWAYS_FATAL_IF(i < 0, "RefBase: removing id %p that doesn't exist!", id);
if (i >= 0) {
int32_t val = --(refs->editValueAt(i));
if (val == 0) {
refs->removeItemsAt(i);
}
}
}
void printRefs(const KeyedVector<const void*, int32_t>& refs)
{
const size_t N=refs.size();
for (size_t i=0; i<N; i++) {
printf("\tID %p: %d remain\n", refs.keyAt(i), refs.valueAt(i));
}
}
mutable Mutex mMutex;
KeyedVector<const void*, int32_t> mStrongRefs;
KeyedVector<const void*, int32_t> mWeakRefs;
#endif
#endif
};
```
这个类在强引用里面也说过,虽然很多,但是很多都不需要关心,有些是在调试时候用的,主要我们看前几个变量,也就是强引用计数值mStrong,弱引用计数值mWeak,引用的对象mBase,引用生命周期控制的方式mFlags。然后它的构造函数初始化了这四个的值,具体在强引用那篇文章里面都有介绍过,这里就不多叙述了。
下面开始说重点的,先看下弱引用指针的类:
```c++
template <typename T>
class wp
{
public:
typedef typename RefBase::weakref_type weakref_type;
inline wp() : m_ptr(0) { }
wp(T* other);
wp(const wp<T>& other);
wp(const sp<T>& other);
template<typename U> wp(U* other);
template<typename U> wp(const sp<U>& other);
template<typename U> wp(const wp<U>& other);
~wp();
// Assignment
wp& operator = (T* other);
wp& operator = (const wp<T>& other);
wp& operator = (const sp<T>& other);
template<typename U> wp& operator = (U* other);
template<typename U> wp& operator = (const wp<U>& other);
template<typename U> wp& operator = (const sp<U>& other);
void set_object_and_refs(T* other, weakref_type* refs);
// promotion to sp
sp<T> promote() const;
// Reset
void clear();
// Accessors
inline weakref_type* get_refs() const { return m_refs; }
inline T* unsafe_get() const { return m_ptr; }
// Operators
COMPARE_WEAK(==)
COMPARE_WEAK(!=)
COMPARE_WEAK(>)
COMPARE_WEAK(<)
COMPARE_WEAK(<=)
COMPARE_WEAK(>=)
inline bool operator == (const wp<T>& o) const {
return (m_ptr == o.m_ptr) && (m_refs == o.m_refs);
}
template<typename U>
inline bool operator == (const wp<U>& o) const {
return m_ptr == o.m_ptr;
}
inline bool operator > (const wp<T>& o) const {
return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
}
template<typename U>
inline bool operator > (const wp<U>& o) const {
return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
}
inline bool operator < (const wp<T>& o) const {
return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
}
template<typename U>
inline bool operator < (const wp<U>& o) const {
return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
}
inline bool operator != (const wp<T>& o) const { return m_refs != o.m_refs; }
template<typename U> inline bool operator != (const wp<U>& o) const { return !operator == (o); }
inline bool operator <= (const wp<T>& o) const { return !operator > (o); }
template<typename U> inline bool operator <= (const wp<U>& o) const { return !operator > (o); }
inline bool operator >= (const wp<T>& o) const { return !operator < (o); }
template<typename U> inline bool operator >= (const wp<U>& o) const { return !operator < (o); }
private:
template<typename Y> friend class sp;
template<typename Y> friend class wp;
T* m_ptr;
weakref_type* m_refs;
};
```
可以看到,弱引用指针类wp也是一个模板类,泛型就是需要引用的对象,它有一个私有变量m_ptr,指向引用的对象,这点和强指针是一样的,然后我们看到,它还有一个变量weakref_type* m_refs,我们通过构造函数,看看它是怎么初始化的。
```c++
template<typename T>
wp<T>::wp(T* other)
: m_ptr(other)
{
if (other) m_refs = other->createWeak(this);
}
template<typename T>
wp<T>::wp(const wp<T>& other)
: m_ptr(other.m_ptr), m_refs(other.m_refs)
{
if (m_ptr) m_refs->incWeak(this);
}
template<typename T>
wp<T>::wp(const sp<T>& other)
: m_ptr(other.m_ptr)
{
if (m_ptr) {
m_refs = m_ptr->createWeak(this);
}
}
```
这3个构造函数意思都是一样的,只不过初始化提供的参数不同,最后都是会转化为createWeak去创建weakref_type类的对象赋值给m_ptr。我们跟进去看下createWeak方法:
```c++
RefBase::weakref_type* RefBase::createWeak(const void* id) const
{
mRefs->incWeak(id);
return mRefs;
}
```
这个方法里面调用mRefs的incWeak:
```c++
void RefBase::weakref_type::incWeak(const void* id)
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
impl->addWeakRef(id);
const int32_t c = android_atomic_inc(&impl->mWeak); // 弱引用计数值+1
LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}
```
再跟进去可以看到最终就是把弱引用计数值加1,可减弱引用指针的构造函数就是把引用的对象的弱引用值加1,这个理解起来很直观。
看完了构造函数,也就是增加弱引用计数值的过程,下面再来看减少弱引用值的过程,自然而然的,就是要看它的析构函数:
```c++
template<typename T>
wp<T>::~wp()
{
if (m_ptr) m_refs->decWeak(this);
}
```
和增加一样,减少对应的是调用引用对象的decWeak函数:
```c++
void RefBase::weakref_type::decWeak(const void* id) // 弱引用减一
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
impl->removeWeakRef(id);
const int32_t c = android_atomic_dec(&impl->mWeak); // 弱引用减1
LOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
if (c != 1) return; // 如果还有弱引用就return
if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) { // 只有0才会进这里,可以理解为只受强引用控制。
if (impl->mStrong == INITIAL_STRONG_VALUE) // 说明没有被强引用引用过,那么就会把强引用没用过的对方释放掉
delete impl->mBase;
else {
// LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
delete impl; // 到这里说被强引用引用过,那么之前decStrong方法的地方,肯定已经被释放掉了,现在既然弱引用也是0了,那么也可以释放imp了,为什么不在~RefBase()析构中呢,因为进入这个分支肯定是之前impl->mBase已经被执行了析构了,所以那时候弱引用可能还不是0,所以在这里在del下
}
} else {
impl->mBase->onLastWeakRef(id);
if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) { // 到这里不等于OBJECT_LIFETIME_FOREVER,说明是既受强引用也受弱引用,那么就可以把强引用的对象释放掉,因为如果进这里分支,前面decStrong中释放强引用的地方肯定没有释放过,不过这里为什么不释放impl呢?因为impl是Refbase中new出来的,所以会在~RefBase()中del
delete impl->mBase;
}
} // 如果以上分支都不是,说明既不受强引用,也不说弱引用,指针指针没有用,需要用户自己手动释放
}
```
这个函数在前面强引用的时候也已经讲过了,上面代码里面也都有注释,就不多说了。看上去好像比强引用要简单,强引用在增加和减少引用值的时候,需要根据不同情况,同时增加和减少弱引用和强引用,而这里弱引用好像只要关系弱引用自己就可以了,不用关心强引用。
正常来说是这样的,但是别忘记了,前面在介绍强引用的时候说过,由于强引用在增加一个引用值的时候,会同时增加强和弱2个引用值,而弱引用增加的时候只会增加弱引用一个值,所以弱引用是大于等于强引用的数量的。而一个智能指针的对象生命周期的控制有3种不同的方法。即只受强引用影响,同时受强引用和弱引用影响,对强引用和弱引用都不受影响,所以有可能存在一个只受强引用影响的对象由于强引用计数为0了,所以被释放,而此时弱引用计数还不为0,所以虽然弱引用指针指向了一个对象,但是实际这个对象已经不存在了,在这种情况下,我们要操作这个对象的话,就需要判断是否这个对象还存在,如果不存在就不可以操作了,所以弱指针的一个难点在判断对象是否存在,主要方法是promote方法:
```c++
template<typename T>
sp<T> wp<T>::promote() const
{
return sp<T>(m_ptr, m_refs);
}
```
可以看到,这个方法很直观,就是把一个弱引用的参数通过强引用指针的构造方法返回一个强引用指针。
```c++
template<typename T>
sp<T>::sp(T* p, weakref_type* refs) // 这个方法是弱引用升级为强引用中调用的,即wp中promote
: m_ptr((p && refs->attemptIncStrong(this)) ? p : 0) // p是具体引用的那个对象,refs是弱引用计数的对象. 如果引用对象p不为空,就调用refs->attemptIncStrong,如果升级成功,就把引用对象赋值给m_ptr(m_ptr是指向引用对象的)
{
}
```
这个构造方法主要就是给强引用中m_ptr赋值,m_ptr指向实际引用的对象,如果该对象不存在就赋值0。判断该对象是否存在通过attemptIncStrong方法,我们在跟进去看。
```c++
bool RefBase::weakref_type::attemptIncStrong(const void* id) // 该方法是把一个弱引用升级为一个强引用中调用的,或者说主要是判断目前这个对象是否存在。最先开始的地方是wp<T>::promote中会调用 sp<T>(m_ptr,m_refs)
{
incWeak(id);
weakref_impl* const impl = static_cast<weakref_impl*>(this);
int32_t curCount = impl->mStrong;
LOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow",
this);
while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) { // 如果强引用数大于0,并且有被赋值过,说明这个对象是存在的,可以转为强引用
if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) { // 该方法目的是把强引用指针的值+1,原值为curCount,现在需要加1,即curCount+1,这个值是是保存在地址&impl->mStrong上的,该方法会判断如果当前这个地址的值等于老的值,即这里参数curCount,那么就修改为curCount+1,并返回0,否则就不做动作,返回1
break; // 修改成功,break
}
curCount = impl->mStrong; // 如果没有修改成功,重新获取老的值,并且while循环重新计算(这里失败可能是其他线程已经对它做了修改)
}
if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) { // 如果强引用数为<=0,或者之前重来没有被引用过,那么就不确定这个对象释放存在,下面就要根据情况来判断
bool allow;
if (curCount == INITIAL_STRONG_VALUE) { // 如果对象重来没有被强引用过
// Attempting to acquire first strong reference... this is allowed
// if the object does NOT have a longer lifetime (meaning the
// implementation doesn't need to see this), or if the implementation
// allows it to happen.
allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK // flag最后一位是0这里的这个!= 才能成立,我们知道mFlags有三种值,0,0x1,0x3,只有0才会成立,而0就代表了只受强引用影响,那么结合上面的if,说明一个对象只受强引用影响,但是又没有被引用过,所以必然没有被释放过,所以这个条件说明对象存在的,运行被升级为强引用
|| impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id); // 到这里,说明mflags是0xxxx1这样的,最低位是1,这个方法就是说明只要最地位是1就可以升级为强指针,我的理解最低位是如果这个类不希望被强引用,这个方法里面会参数FIRST_INC_STRONG的处理操作肯定是会返回false的
} else { // 到这里说明曾经被强引用引用过,但是现在没有被强引用引用了
// Attempting to revive the object... this is allowed
// if the object DOES have a longer lifetime (so we can safely
// call the object with only a weak ref) and the implementation
// allows it to happen.
allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK // 这里等号成立的话,说明mFlags可能是OBJECT_LIFETIME_WEAK,也可能是OBJECT_LIFETIME_FOREVER。对于OBJECT_LIFETIME_WEAK是既受强指针影响,也受弱指针影响,并且都等于0时才会被自动释放,现在弱指针明显不是0,所以对象肯定存在。对于OBJECT_LIFETIME_FOREVER是既不受强指针也不受弱指针影响,并且只有开发者自己手动才会释放,所以目前肯定没有被手动释放过,所以对象肯定也是存在的。
&& impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id); // 这里的和上面一样,只要对象mFlags最低位是1,就允许转为强指针。
}
if (!allow) { // 到这里说明升级为强指针失败
decWeak(id); // 因为失败了,本函数第一行调用过incWeak,所以现在要重新减回来
return false;
}
curCount = android_atomic_inc(&impl->mStrong); // 到这里说明可以成功升级为强指针,对强指针引用+1,主要这里执行后,如果没有其他线程对impl->mStrong进行过操作,那么curCount的值应该是修改前的值,即要么是<=0,要么是等于INITIAL_STRONG_VALUE
// If the strong reference count has already been incremented by
// someone else, the implementor of onIncStrongAttempted() is holding
// an unneeded reference. So call onLastStrongRef() here to remove it.
// (No, this is not pretty.) Note that we MUST NOT do this if we
// are in fact acquiring the first reference.
if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) { // 到这里curCount的值说明已经有其他线程修改过了,所以可以在onLastStrongRef进行一些操作
impl->mBase->onLastStrongRef(id);
}
}
impl->addWeakRef(id);
impl->addStrongRef(id);
#if PRINT_REFS
LOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
#endif
if (curCount == INITIAL_STRONG_VALUE) { // 如果curCount是INITIAL_STRONG_VALUE,这里是第一次被加1,由于初始值INITIAL_STRONG_VALUE不是0,所以下面一句通过-INITIAL_STRONG_VALUE,把curCount置成1
android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong); // 第一次设置强指针引用值,把curCount置成1
impl->mBase->onFirstRef();
}
return true;
}
```
这个方法开始先执行incWeak,给弱引用加1,通过前面强引用分析我们说过,增加一个强引用的同时会增加一个弱引用,这里就先增加一个弱引用。
接着这段
```c++
int32_t curCount = impl->mStrong;
while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
break;
}
curCount = impl->mStrong;
}
```
如果强引用大于0,说明当前对象肯定是存在的,那么我们就给强引用加1,然后就break可以返回了。这里由于android_atomic_cmpxchg这个方法不是线程安全的,所以有可能会修改失败,通过不断对比新老值是否修改了,才能正确判断是否修改成功。
再接下去看后面的情况,如果curCount <= 0 || curCount == INITIAL_STRONG_VALUE的情况,先看如果对象重来没有被引用过,即curCount == INITIAL_STRONG_VALUE,会有下面代码:
```c++
allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
|| impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
```
impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK这句如果成立表明,这个对象只受强引用影响,既然一个对象只受强引用影响,而他又没有被释放过,那么那么对象现在必然存在。如果这句不成立,即表面对象可能同时受到强弱引用影响或者强弱引用都不受影响,不管是哪种对象也肯定都存在,因为如果同时受强弱引用影响,只有当弱指针引用为0的时候对象才会被释放,现在正在处理的就是弱引用,所以弱引用不为0,对象肯定存在。而都不受影响的话,说明开发者自己会手动处理对象。这里就算对象是不存在的也是开发者的问题,我们不用考虑。所以会调用onIncStrongAttempted这个方法。这个方法是什么用的呢,简单说就是来看下这个对象是否允许被用做强引用,这个怎么理解?因为有可能某些对象在设计的时候就是不希望被强引用的,这个方法默认返回的是true,表面默认对象都是允许被强引用的,如果真的有人设计了个不希望被强引用的对象,那么这个方法有可能被覆写,所以我们有必要看下这个对象的这个方法是否允许被强引用。
好了,到这里主要的处理逻辑基本就结束了,下面根据结果做一些处理:
```c++
if (!allow) { // 到这里说明升级为强指针失败
decWeak(id); // 因为失败了,本函数第一行调用过incWeak,所以现在要重新减回来
return false;
}
```
如果不允许被强引用,弱引用计数减1,因为前面开始就加1了。
```c++
curCount = android_atomic_inc(&impl->mStrong);
if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {
impl->mBase->onLastStrongRef(id);
}
```
最后把强引用加1,这里if (curCount > 0 && curCount < INITIAL_STRONG_VALUE)如果进入这个分支,说明有可能在增加强引用后,其他线程可能已经做了修改,因为按照这里的逻辑android_atomic_inc返回是修改前的值,这里curCount修改前要么是<=0,要么是INITIAL_STRONG_VALUE,所以如果不能这些值,可以做一些处理。
最后如果curCount等于INITIAL_STRONG_VALUE,那么说明是第一次引用,而INITIAL_STRONG_VALUE的值不是1,所以在加1后,再减去INITIAL_STRONG_VALUE保证值是1
```c++
if (curCount == INITIAL_STRONG_VALUE) {
android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong); // 第一次设置强指针引用值,把curCount置成1
impl->mBase->onFirstRef();
}
```
至此弱引用指针中最关键的这个方法就说完了,弱引用的增加和减少都是比较直接的,直接把弱引用计数器增减就可以了,但是之所以要有promote这个方法,是因为弱引用指针中没有重载操作符*和->,所以我们也获取不到对象,只有升级到强指针才能获取真正的对象,可以看到强引用中有以下的操作符重载:
```c++
inline T& operator* () const { return *m_ptr; }
inline T* operator-> () const { return m_ptr; }
inline T* get() const { return m_ptr; }
```
通过解引用和箭头操作符可以操作m_ptr,但是弱引用中是没有的,所以必须要升级到强引用,而强引用又不一定存在,所以需要promote方法来做处理。
最后有个小方法可以单独说一下,就是修改声明周期控制变量的mFlags方法:
```c++
void RefBase::extendObjectLifetime(int32_t mode) // 把对象mFlags设置为mode,即0(只受强指针),OBJECT_LIFETIME_WEAK(同时受强和弱指针) OBJECT_LIFETIME_FOREVER(强和弱都不受)
{
android_atomic_or(mode, &mRefs->mFlags);
}
```
可以看到如果要修改声明周期的控制方式,只要调用extendObjectLifetime这个方法,用来和原mFlags作或操作就可以了,这个方法前面没说,但是还是mFlags这个变量还是很重要的,所以特地这里提一下。
好了,以上就是弱引用指针的全部内容了,下面通过一个强引用和弱引用的使用例子,来加强理解,代码如下:
```c++
class WeightClass : public RefBase
{
public:
void printRefCount()
{
int32_t strong = getStrongCount();
weakref_type* ref = getWeakRefs();
printf("-----------------------\n");
printf("Strong Ref Count: %d.\n", (strong == INITIAL_STRONG_VALUE ? 0 : strong));
printf("Weak Ref Count: %d.\n", ref->getWeakCount());
printf("-----------------------\n");
}
};
class StrongClass : public WeightClass
{
public:
StrongClass() // 默认只受强引用影响
{
printf("Construct StrongClass Object.\n");
}
virtual ~StrongClass()
{
printf("Destory StrongClass Object.\n");
}
};
class WeakClass : public WeightClass
{
public:
WeakClass()
{
extendObjectLifetime(OBJECT_LIFETIME_WEAK); // 改变生命周期控制方式,同时受强弱引用影响
printf("Construct WeakClass Object.\n");
}
virtual ~WeakClass()
{
printf("Destory WeakClass Object.\n");
}
};
class ForeverClass : public WeightClass
{
public:
ForeverClass()
{
extendObjectLifetime(OBJECT_LIFETIME_FOREVER); // 改变生命周期控制方式,不受强弱引用影响
printf("Construct ForeverClass Object.\n");
}
virtual ~ForeverClass()
{
printf("Destory ForeverClass Object.\n");
}
};
void TestStrongClass(StrongClass* pStrongClass)
{
wp<StrongClass> wpOut = pStrongClass; // 弱引用指针
pStrongClass->printRefCount(); // 弱引用1,强引用0
{
sp<StrongClass> spInner = pStrongClass; // 强引用指针
pStrongClass->printRefCount(); // 弱引用2,强引用1
}
sp<StrongClass> spOut = wpOut.promote(); // 此时退出强引用作用域,弱引用1,强引用0,由于默认声明控制方式是只受强引用影响,所以会delete对象,promote会失败
printf("spOut: %p.\n", spOut.get()); // 打印为0
}
void TestWeakClass(WeakClass* pWeakClass)
{
wp<WeakClass> wpOut = pWeakClass; // 弱引用指针
pWeakClass->printRefCount(); // 弱引用1,强引用0
{
sp<WeakClass> spInner = pWeakClass; // 强引用指针
pWeakClass->printRefCount(); // 弱引用2,强引用1
}
pWeakClass->printRefCount(); // 此时退出强引用作用域,弱引用1,强引用0,由于同时受强弱引用影响,不会delete对象
sp<WeakClass> spOut = wpOut.promote(); // 提升会成功
printf("spOut: %p.\n", spOut.get());
}
void TestForeverClass(ForeverClass* pForeverClass) // 不受强弱指针影响,不会自动delete对象
{
wp<ForeverClass> wpOut = pForeverClass;
pForeverClass->printRefCount();
{
sp<ForeverClass> spInner = pForeverClass;
pForeverClass->printRefCount();
}
}
int main(int argc, char** argv)
{
printf("Test Strong Class: \n");
StrongClass* pStrongClass = new StrongClass();
TestStrongClass(pStrongClass); // 只受强引用影响
printf("\nTest Weak Class: \n");
WeakClass* pWeakClass = new WeakClass();
TestWeakClass(pWeakClass); // 同时受强弱引用影响
printf("\nTest Froever Class: \n");
ForeverClass* pForeverClass = new ForeverClass();
TestForeverClass(pForeverClass); // 不受强弱引用影响
pForeverClass->printRefCount();
delete pForeverClass;
return 0;
}
```
可以看到分别是3个类,强引用,弱引用,和ForeverClass(不知道怎么翻译,就是强弱都不受影响的类)。 大家可以关注下三个测试方法TestStrongClass,TestWeakClass,TestForeverClass,里面已经注释了,在相关引用方法类自动释放的情况。基本上这个理解了这几个测试方法就基本理解了智能指针了。
Android的智能指针就说到这里了,最后总结下3种不同生命控制周期在智能指针析构时候对于对象的影响。
一. mFlag == 0,即只受强引用影响
这种情况分为强引用值等于0,大于0,等于INITIAL_STRONG_VALUE(1<<28)的情况。 强引用值减一后等于0,delete对象。 弱引用值减一后等于0,如果强引用值等于INITIAL_STRONG_VALUE,delete对象,否则deleteimpl(弱引用值为0了,强引用必定小于等于0,或者等于INITIAL_STRONG_VALUE)
二. mFlag == OBJECT_LIFETIME_WEAK(0x0001) 同时受强弱引用影响。
强引用减一后不做什么操作,继续弱引用减一,如果弱引用减一后等于0了,说明强引用要么0,要么INITIAL_STRONG_VALUE,不可能大于等,所以delete对象。
三. mFlag == OBJECT_LIFETIME_FOREVER(0x0003) 不受强弱引用影响。不会自动delete对象,需要手动释放。
Android智能指针之弱引用指针