5.2.2 第二板斧–由弱生强
最后更新于:2022-04-02 05:49:44
再看第二个例子,代码如下所示:
**例子2**
~~~
int main()
{
A *pA =new A();
wp wpA(A);
sp spA = wpA.promote();//通过promote函数,得到一个sp。
}
~~~
对A的wp化,不再做分析了。按照前面所学的知识,wp化后仅会使弱引用计数加1,所以此处wp化的结果是:
- 影子对象的弱引用计数为1,强引用计数仍然是初始值0x1000000。
wpA的promote函数是从一个弱对象产生一个强对象的重要函数,试看:
1. 由弱生强的方法
代码如下所示:
**RefBase.h**
~~~
template
sp wp::promote() const
{
returnsp(m_ptr, m_refs); //调用sp的构造函数。
}
~~~
**RefBase.h**
~~~
template
sp::sp(T* p, weakref_type* refs)
: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**
~~~
boolRefBase::weakref_type::attemptIncStrong(const void* id)
{
incWeak(id);//增加弱引用计数,此时弱引用计数变为2
weakref_impl* const impl = static_cast(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();
}
returntrue; //由弱生强成功
}
~~~
3. 第二板斧的结果
promote完成后,相当于增加了一个强引用。根据上面所学的知识可知:
- 由弱生强成功后,强弱引用计数均增加1。所以现在影子对象的强引用计数为1,弱引用计数为2。
';