5.2.2 第二板斧——由弱生强

再看第二个例子,代码如下所示:

[—>例子2]


int main()

{

A*pA=new A();

wp<A>wpA(pA);

sp<A>spA=wpA.promote();//通过promote函数,得到一个sp。

}


对A的wp化,不再做分析了。按照前面所讲的知识,wp化后仅会使弱引用计数加1,所以此处wp化的结果是:

影子对象的弱引用计数为1,强引用计数仍然是初始值0x1000000。

wpA的promote函数是从一个弱对象产生一个强对象的重要函数,试看————

1.由弱生强的方法

代码如下所示:


[—>RefBase.h]

template<typename T>

sp<T>wp<T>:promote()const

{

return sp<T>(m_ptr,m_refs);//调用sp的构造函数。

}

[—>RefBase.h]

template<typename T>

sp<T>:sp(Tp,weakref_typerefs)

:m_ptr((p&&refs->attemptIncStrong(this))?p:0)//有点看不清楚。

{

//上面那行代码够简洁,但是不方便阅读,我们写成下面这样:

/*

T*pTemp=NULL;

//关键函数attemptIncStrong

if(p!=NULL&&refs->attemptIncStrong(this)==true)

pTemp=p;

m_ptr=pTemp;

*/

}


2.成败在此一举

由弱生强的关键函数是attemptIncStrong,它的代码如下所示:


[—>RefBase.cpp]

bool RefBase:weakref_type:attemptIncStrong(const void*id)

{

incWeak(id);//增加弱引用计数,此时弱引用计数变为2。

weakref_implconst impl=static_cast<weakref_impl>(this);

int32_t curCount=impl->mStrong;//这个仍是初始值。

//下面这个循环,在多线程操作同一个对象时可能会循环多次。这里可以不去管它,

//它的目的就是使强引用计数增加1。

while(curCount>0&&curCount!=INITIAL_STRONG_VALUE){

if(android_atomic_cmpxchg(curCount,curCount+1,&impl->mStrong)==0){

break;

}

curCount=impl->mStrong;

}

if(curCount<=0||curCount==INITIAL_STRONG_VALUE){

bool allow;

/*

下面这个allow的判断极为精妙。impl的mBase对象就是实际对象,有可能已经被delete了。

curCount为0,表示强引用计数肯定经历了INITIAL_STRONG_VALUE->1->……->0的过程。

mFlags就是根据标志来决定是否继续进行||或&&后的判断,因为这些判断都使用了mBase,如不做这些判断,一旦mBase指向已经回收的地址,你就等着segment fault吧!

其实,咱们大可不必理会这些东西,因为它不影响我们的分析和理解。

*/

if(curCount==INITIAL_STRONG_VALUE){

allow=(impl->mFlags&OBJECT_LIFETIME_WEAK)!=OBJECT_LIFETIME_WEAK

||impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG,id);

}else{

allow=(impl->mFlags&OBJECT_LIFETIME_WEAK)==OBJECT_LIFETIME_WEAK

&&impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG,id);

}

if(!allow){

//allow为false,表示不允许由弱生强,弱引用计数要减去1,这是因为咱们进来时加过一次。

decWeak(id);

return false;//由弱生强失败。

}

//允许由弱生强,强引用计数要增加1,而弱引用计数已经增加过了。

curCount=android_atomic_inc(&impl->mStrong);

if(curCount>0&&curCount<INITIAL_STRONG_VALUE){

impl->mBase->onLastStrongRef(id);

}

}

impl->addWeakRef(id);

impl->addStrongRef(id);//两个函数调用没有作用。

if(curCount==INITIAL_STRONG_VALUE){

//强引用计数变为1。

android_atomic_add(-INITIAL_STRONG_VALUE,&impl->mStrong);

//调用onFirstRef,通知该对象第一次被强引用。

impl->mBase->onFirstRef();

}

return true;//由弱生强成功。

}


3.第二板斧的结果

promote完成后,相当于增加了一个强引用。根据上面所学的知识可知:

由弱生强成功后,强弱引用计数均增加1。所以现在影子对象的强引用计数为1,弱引用计数为2。