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。