We use RefCount to manage the life circle of a pointer.
1 RefCounted/RefCountedBase
this is a basic class , it has a variant "m_refCount" used for counting the reference of it's usage.
it also has two very most import function "ref()" and "deref()" which will add and subtract the reference count by one.
a.RefCountedBase<--RefCounted
RefCountedBase is a base class
RefCounted is a class template inherited from RefCountedBase
template<typename T> class RefCounted :
public RefCountedBase, public Noncopyable {
...
}
b.RefCountedBase::derefBase() // cutting down the count of the pointer
c. RefCounted::deref() //after calling derefBase(), call "delete" to free the pointer.
most class of the Webkit inherit from it. such as:
class HTMLCollection : public RefCounted<HTMLCollection> {
......
}
d. in RefCountedBase
RefCountedBase()
: m_refCount(1)
the count is set to "1" in it's default constructure function.
2 RefPtr/PassRefPtr
They are two Class Templates which need a class inherited from RefCounted as it's class parameter "T".
The most imporant usage of RefPtr is to count the reference of the "T", the class parameter for the template.
It manage it by two ways
a. in construction and destruction functions
PassRefPtr(T* ptr) : m_ptr(ptr) { refIfNotNull(ptr); }
ALWAYS_INLINE ~PassRefPtr() { derefIfNotNull(m_ptr); }
refIfNotNull and derefIfNotNull
template<typename T> REF_DEREF_INLINE void refIfNotNull(T* ptr)
{
if (LIKELY(ptr != 0))
ptr->ref();
}
template<typename T> REF_DEREF_INLINE void derefIfNotNull(T* ptr)
{
if (LIKELY(ptr != 0))
ptr->deref();
}
b.overriding the operator=
there are many implementations of operator(), which will change the reference count seperately, depending on the parameter of the function.
PassRefPtr& operator=(T*);
PassRefPtr& operator=(const PassRefPtr&);
PassRefPtr& operator=(std::nullptr_t) { clear(); return *this; }
in all these functions, it default copy constructure function will be called. so the ref will be added.
The offical website of webkit talk something about PassRefPtr. Since using RefPtr lonely will cause the count churn, we import it to reduce it.
Why could PassRefPtr reduce such churn?
The most imporant is just as we talk about above, the implementation of operator=()
a, It will add the reference by one, if the parameter is a type of RefPtr.
b.But the count will not change if the type is PassRefPtr,
We just use PassRefPtr for function parameters.
3 RefPtr to PassRefPtr
release(), a function of RefPtr, which will change a RefPtr to a PassRefPtr, without changing it's reference.
the implement is as follow (in RefPtr.h ):
PassRefPtr<T> release() { PassRefPtr<T> tmp = adoptRef(m_ptr); m_ptr = 0; return tmp; }
template<typename T> inline PassRefPtr<T> adoptRef(T* p)
{
adopted(p);
return PassRefPtr<T>(p, true);
}
inline void adopted(const void*) { }
in practice we just use RefPtr's private member "m_ptr", to generate a PassRefPtr class without changing it's reference.
PassRefPtr(T* ptr, bool) : m_ptr(ptr) { }
mutable T* m_ptr;
in the end, it turns to be an opeartion of the default copy constructor of the T, who derives from RefCountedBase.
It will also copy the m_refCount value from "ptr" to "m_ptr", which will ensure the return PassRefPtr to have the same refCount of RefPtr
1.OwnerPtr
目的:保证一个类析构的时候,其内部指针指向的内存也被释放。
实现:
a.在该类的构造函数创建一个智能指针对象,因此在析构的时候,就会调用该指针的析构函数。
b.然后在该智能指针的析构函数中,释放指针指向的内存。
Owner用法
a.作为成员变量
构造时候创建,析构的时候自动会销毁
b.传递给其他函数
严格讲OwnerPtr的目的就是控制一个指针的所有权,不用来传递。
因此如果需要传递,需要借助一个中间类PassOwnerPtr,将自己清空,内容和所有权交给PassOwnerPtr。
c.在某一个函数中
一般来讲,从某一个函数传递过来的变量类型一般是PassOwnerPtr
在函数中第一件事情,应该是要把PassOwnerPtr转换为Owner
此时,我们是用一个函数临时变量的生命周期来管理这个指针,而不是像第一种情形,用类的生命周期来管理指针。
2.RefPtr
目的:当一个指针在多个类之间传递,而且在很多类中间都有可能释放其指向的内存空间,为了实现该内存的自动释放,引入智能指针RefPtr。
(只有指针在某一个函数传递,该函数可能会持有该指针的时候,我们才需要向这个函数传递智能指针
换言之,如果这个函数仅仅是从这个指针取一个值,并不保留对该指针内容的引用,那么就不需要智能指针)
实现:
a.创建一个具有引用计数的基类
RefCountBase、RefCount
在RefCountBase和RefCount,有两个函数:
ref()用户增加计数器
derefBase()/deref()用于减少计数器
b、创建其他的实体类,继承于RefCount
c、创建包含其他类指针的智能指针RefPtr
在其构造和赋值函数中对引用计数器加1
在其析构函数对引用计数器减一,并且在计数为1的时候删除其他指针指向的内存。
3.PassRefPtr
“Since using RefPtr lonely will cause the count churn, we import it to reduce it.”
PassRefPtr特点:
a. 把它赋值给别人,引用计算器不变
b. 把它赋值给别人,它自身的指针变为空。
所以我们在给指针赋值给临时变量的时候,可以用PassRefPtr,避免赋值+1,析构-1,这种count churn。
但是由于PassRefPtr给别人赋值后,自己后变为NULL,所以PassRefPtr只能应用于如下场景:(都是赋值给别人后,自己就不在被用到)
a. 函数参数(对于PassRefPtr的参数,应该立即用RefPtr类型保存一下,然后使用)
b. 函数返回值
4.PassRefPtr作为参数
但是在webkit我们却见到如下代码,函数定义的形参用的是 template<typename T> class PassRefPtr
但是实际使用该函数的时候,直接传递的是 template<typename T> class RefPtr这种指针呢?
因为PassRefPtr有一个 传入 RefPtr这样的拷贝构造函数
template<typename T> template<typename U> inline PassRefPtr<T>::PassRefPtr(const RefPtr<U>& o)
: m_ptr(o.get())
{
T* ptr = m_ptr;
refIfNotNull(ptr);
}
PassRefPtr对于RawPointer的构造函数,引用计数器仍然是+1了的
//个人还是感觉加了1,然后在ptr析构的时候,又减了1.
貌似也是引起了“count churn”,不过比起RefPtr要少一次,如下程序:
void TestRefPtr(RefPtr <CTest> test)
{
RefPtr <CTest>b = test;
}
void TestPassRefPtr(PassRefPtr <CTest> test)
{
RefPtr <CTest>b = test;
}
main()
{
RefPtr <CTest> original = new CTest();
TestRefPtr(original);//+1+1,-1-1
TestPassRefPtr(original);//+1-1,减少count churn
}
5. PassRefPtr 作为函数的返回值
PassRefPtr有1个不带参数的构造函数:
PassRefPtr() : m_ptr(0) { }
PassRefPtr有2个以原始指针为参数的构造函数:
a PassRefPtr(T* ptr) : m_ptr(ptr) { refIfNotNull(ptr); }
b PassRefPtr(T* ptr, bool) : m_ptr(ptr) { }
第一个函数对引用计数器进行了操作。
而第二个函数没有,不过第二个是私有函数,我们要通过其友元才来调用。
template<typename T> inline PassRefPtr<T> adoptRef(T* p)
{
adopted(p);
return PassRefPtr<T>(p, true);
}
对于以原始指针为参数的构造函数,
如果使得到的PassRefPtr引用不变,必须采用adoptRef来调用。
由于所有对象的基类RefCountedBase,在构造函数的时候是把RefCount置为1的,因此所有的创建函数都是如下实现:
static PassRefPtr<CLyftest> create() { return adoptRef(new CLyftest()); }
只有这样才能保证,创建的PassRefPtr引用计数器是1,否则就被+1了。.
所以,为了保证返回值的引用计数器正确,以PassRefPtr作为返回值,一般要么以“PassRefPtr() ”返回,要么用adoptRef返回。
6.PassRefPtr to RefPtr
a.PassRefPtr.releaseRef();
b.PassRefPtr.leakRef();
c.采用RefPtr的构造函数
template<typename T> template<typename U> inline RefPtr<T>::RefPtr(const
PassRefPtr<U>& o): m_ptr(o.leakRef())
{
}
其内部实现也是调用的PassRefPtr.leakRef();
template<typename T> inline T* PassRefPtr<T>::leakRef() const
{
T* ptr = m_ptr;
m_ptr = 0;
return ptr;
}
PassRefPtr的指针被置空,而把原始指针的地址以返回值的形式返回。
7. RefPtr to PassRefPtr
PassRefPtr<T> release() { PassRefPtr<T> tmp = adoptRef(m_ptr); m_ptr = 0; return tmp; }
本质也是调用的adoptRef。 没有改变计数器(参照5,PassRefPtr的构造函数)
,而且之前的RefPtr也被置空了。
8. OwnerPtr和PassOwnerPtr之间关系
于
RefPtr和PassRefPtr类似
下表的关系也一样
7.附:
1、构造函数和引用计数器
RawPointer、RefPtr、PassRefPtr之间相互转化对引用计数器的影响
一、构造函数
to from | Raw Pointer | RefPtr | PassRefPtr |
RawPointer | -- | -- | -- |
RefPtr | add | add | no |
PassRefPtr | add | add | no |
1.Code to RefPtr
a. Raw Pointer to RefPtr //add
ALWAYS_INLINE RefPtr(T* ptr) : m_ptr(ptr) { refIfNotNull(ptr); }
b. RefPtr to RefPtr //add
ALWAYS_INLINE RefPtr(const RefPtr& o) : m_ptr(o.m_ptr) { refIfNotNull(m_ptr); }
c. PassRefPtr to RefPtr //Do not add
template<typename T> template<typename U> inline RefPtr<T>::RefPtr(const PassRefPtr<U>& o) : m_ptr(o.leakRef())
{
}
2.Code to PassRefPtr
a. Raw Pointer to PassRefPtr //add
PassRefPtr(T* ptr) : m_ptr(ptr) { refIfNotNull(ptr); }
(private)
PassRefPtr(T* ptr, bool) : m_ptr(ptr) { }//Do not add
template<typename T> inline PassRefPtr<T> adoptRef(T* p)
{
adopted(p);
return PassRefPtr<T>(p, true);
}//only use adoptRef do not change
b.RefPtr to PassRefPtr //add
template<typename T> template<typename U> inline PassRefPtr<T>::PassRefPtr(const RefPtr<U>& o): m_ptr(o.get())
{
T* ptr = m_ptr;
refIfNotNull(ptr);
}
C. PassRefPtr to PassRefPtr //Do not add
PassRefPtr(const PassRefPtr& o) : m_ptr(o.leakRef()) { }
template<typename U> PassRefPtr(const PassRefPtr<U>& o) : m_ptr(o.leakRef()) { }
二、拷贝构造函数
TYPE |
|
RefPtr | Add |
PassRefPtr | No |
a. RefPtr's copy constructure //add
ALWAYS_INLINE RefPtr(const RefPtr& o) : m_ptr(o.m_ptr) { refIfNotNull(m_ptr); }
b. PassRefPtr's copy constructure //add
PassRefPtr(const PassRefPtr& o) : m_ptr(o.leakRef()) { }
template<typename U> PassRefPtr(const PassRefPtr<U>& o) : m_ptr(o.leakRef()) { }
三、赋值构造函数
to from | Raw Pointer | RefPtr | PassRefPtr |
RawPointer | -- | -- | -- |
RefPtr | add | add | no |
PassRefPtr | -- | -- | -- |
1.Code to RefPtr
a. Raw Pointer to RefPtr //add
template<typename T> inline RefPtr<T>& RefPtr<T>::operator=(T* optr)
{
refIfNotNull(optr);
T* ptr = m_ptr;
m_ptr = optr;
derefIfNotNull(ptr);
return *this;
}
b. RefPtr to RefPtr //add
template<typename T> template<typename U> inline RefPtr<T>& RefPtr<T>::operator=(const RefPtr<U>& o)
{
T* optr = o.get();
refIfNotNull(optr);
T* ptr = m_ptr;
m_ptr = optr;
derefIfNotNull(ptr);
return *this;
}
c. PassRefPtr to RefPtr //Do not add
template<typename T> inline RefPtr<T>& RefPtr<T>::operator=(const PassRefPtr<T>& o)
{
T* ptr = m_ptr;
m_ptr = o.leakRef();
derefIfNotNull(ptr);
return *this;
}
2.PassRefPtr hasn't override "=" operator.