一、
RefBase是引用计数的类,它封装了引用计数的技术细节。包括增加强引用计数,增加弱引用计数,减少强引用计数,减少弱引用计数等等。
但是对RefBase的具体操作,却是委托给了weakref_impl这个类。就好比RefBase是一块农田,对农田的操作由weakref_impl这个农夫来操作。weakref_impl是RefBase内部定义的一个类weakref_type的派生类。强和弱引用计数的实际数据也是放在weakref_impl中的.下面是 weakref_impl这个类的定义
class RefBase::weakref_impl 表示它是RefBase的内部类
public RefBase::weakref_type 表示它继承RefBase的内部类weakref_type
class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
std::atomic mStrong; //强引用计数
std::atomic mWeak; //弱引用计数
RefBase* const mBase; //实际对象的影子
std::atomic mFlags;
...
...
...
};
注意RefBase* const mBase这个成员. 任意一个类,当他需要使用引用计数时,都需要继承RefBase这个类。在weakref_impl中设置这么一个RefBase类型的成员是什么用意?我们先看一下RefBase的构造函数,因为实际对象在构造时
父类构造必须被率先调用,c++的多态!RefBase::RefBase():mRefs(new weakref_impl(this))
{
//代码略
}
请看初始化代码mRefs(new weakref_impl(this))也就是说父类在构造的时候,先new了一个new weakref_impl,去初始化mRefs成员,这说明,RefBase这块农田内置了一个农夫weakref_impl,且这个农田的农夫在构造时诞生了!
weakref_impl(RefBase* base)
: mStrong(INITIAL_STRONG_VALUE)
, mWeak(0)
, mBase(base)
, mFlags(0)
{
}
weakref_impl的mBase成员保存的就是传递的this啊,前面说过这个this就是实际对象哦。所以,可以说weakref_impl保存了一个实际对象的引用.
现在可以看sp。sp使用了模板技术,先看一下sp的构造函数
template
sp::sp(T* other):m_ptr(other)
{
if(other)other->incStrong(this);
}
T就代表着实际对象,已知实际对象是继承了RefBase的。m_ptr是sp的成员,类型就是T*,由此可见,强引用类sp内部保存了一个实际对象的引用,由成员m_ptr保存。且sp构造时调用了other->incStrong(this);
void RefBase::incStrong(const void *id)
{
weakref_impl *const refs = mRefs;
refs->addWeakRef(id); //空函数
refs->incWeak(id);
refs->addStrongRef(id);
...
...
...
}
原来在IncStrong()中生成了一个weakref_impl的指针,而这个指针等价于RefBase的成员mRefs. 前面说过了,mRefs就是指向着weakref_impl的。从而通过这个指针调用weakref_impl内部的方法实现了实际数值的改变。由此可见确实是weakref_impl在实际操作引用计数的数值。
RefBase::RefBase():mRefs(new weakref_impl(this))
{
//再看一眼RefBase的构造把,再次确定一下mRefs就是指向weakref_impl
}
现在脉络有点清晰了。sp在构造的时候,首先将实际对象给保存起来了。
而实际对象因为它继承自RefBase, RefBase内部又保存着weakref_impl这个农夫的对象指针(农夫负责操作RefBase这块农田,农夫内部保存着实际的引用计数数值和实际对象). 所有虽然sp只保存了一个实际对象,但是只要sp愿意,它也可以定位到农夫,不是吗?templete
wp::wp(const sp& other):m_ptr(other.m_ptr)
{
if(m_ptr)
m_refs = m_ptr->createWeak(this);
}
m_ptr是T* 类型,同上面介绍sp时细述的一样,那这个createWeak()不出意外就是RefBase的方法咯,过去看看这个createWeak的实现
RefBase::weakref_type* RefBase::createWeak(const void*id) const
{
mRef->incWeak(id);
return mRef;
}
哈,基类RefBase的mRef就是weakref_impl*类型嘛,mRef->incWeak()不就是调用weakref_impl的方法吗?绕一圈还是调用weakref_impl的incWeak()去给弱引用计数+1,并且返回weakref_impl* 给wp的m_Refs成员。
wp 有weakref_impl m_Refs成员,也有T* m_ptr,已知m_ptr是保存了实际对象的引用的,m_Refs代表着weakref_impl;
sp会令强引用计数+1,弱引用计数+1
wp会令弱引用计数+1
wp::~wp()
{
if(m_ptr)m_refs->decWeak(this);
}
去调用weakref_impl的decWeak(),参数是wp的this,
void RefBase::weakref_type::decWeak(const void* id)
{
//原子级操作减少弱引用计数,代码略
if(弱引用!=1)return; //弱引用没到0,就直接返回了
//如果走到这里,弱引用计数应该是为0,
if(xxx)//如果对象不受弱引用控制
{
if(强引用==初始值)
delete impl->mBase; //干掉实际对象
else
delete impl; //农夫给干掉了
}
else
{
if(xxx) //如果既不受强引用控制也不受弱引用控制
delete impl->mBase; //干掉实际对象
}
}
可以看出来,在函数先进行一次原子级操作,将弱引用计数-1之后。当弱引用计数==0的情况下,函数才回继续干活,否则函数立刻返回。wp的析构时是有可能干掉实际对象或者农夫impl的。
template
sp::~sp()
{
if(m_ptr)m_ptr->decStrong(this);
}
根据多态,实际上调用的是RefBase的decStrong()
void RefBase::decStrong(const void *id)
{
//原子级操作,减少强引用计数,代码略过
if(xx) //如果强引用计数==0
{
if(不受弱引用控制)
delete this; //干掉实际对象,因为m_pter调用的decStrong().this就是实际对象
}
refs->decWeak();
}
RefBase::~RefBase()
{
if(mRefs->mWeak==0)
{
delete mRefs;
}
}
我们再捋一下流程:
因为如果对象生命周期仅受到强引用计数控制,在decStrong()中会先干掉实际对象,而实际对象析构时跑到RefBase的析构中,顺带着把weakref_impl也给干掉了,
皆大欢喜,农田农夫都没了,sp也没有了,实际对象也没有了,清理的很干净。虽然decWeak()在函数底部被调用,但是它不做事,进去就返回了。很复杂很绕,分析的应该还不是很完整,但是学到不少,尤其是之前学类的时候,完全没有注意到的细节,很有帮助!