类名: template <class T> class scoped_refptr (scoped_refptr<T>)
定义了一个被管理的裸指针: T* ptr_。
在scoped_refptr<T>被构造时:
constexpr scoped_refptr(T* p) : ptr_(p) { if (ptr_) AddRef(ptr_); //<---- }
以向ptr_添加一个引用。关于AddRef,定义则是:
template <typename T> void scoped_refptr<T>::AddRef(T* ptr) { ptr->AddRef(); //<---- }
这意味着,被管理的类<T>也一定要实现AddRef。同理Release也要实现。而在实际使用时,类也一般会继承RefcountedKeyedService之类的带有计数模板的类。
关于计数模板的相关内容后面再说,先看看哪些操作会导致计数的变化。
对于T而言,
1. 引用计数增长
scoped_refptr<T>构造 | public 调用T->AddRef() |
AddRef | private 调用T->AddRef() |
多个scoped_refptr<T>引用同一个T | 事实上就是多次调用了构造函数。而计数器存在T中,并不是scoped_refptr<>中,所以T的计数会随之增加 |
operator=(T* p) | 生成一个scoped_refptr<T>并赋值,构造的时候引用计数增加 |
2. 引用计数减少
scoped_refptr<T>析构 | public 调用T->Release() |
Release() | private 调用T->Release() |
reset() | public void reset() { scoped_refptr().swap(*this); } 在栈上临时构造一个空的scoped_refptr并转移当前的scoped_refptr到里面去。 当本函数退出时,scoped_refptr析构,计数减一 |
swap() | public *是否析构视情况而定,reset()也是调用了swap() |
3. 引用计数不变
get() | public |
Move Constructor | public |
release() | public 首字母小写的release。释放所有权。 但是因为计数器存在T中,而不是scoped_refptr<>中,所以释放所有权并不会导致任何计数变化 |
RefcountedKeyedService的继承关系如下:
class RefcountedKeyedService : public base::RefCountedThreadSafe<RefcountedKeyedService, impl::RefcountedKeyedServiceTraits>
对于RefCounted/RefCountedThreadedSafe来说,默认它会引用DefaultRefCountedTraits来进行清理工作。
template <class T, typename Traits> class RefCounted; //<-- RefCounted<T, Traits> template <typename T> struct DefaultRefCountedTraits { static void Destruct(const T* x) { RefCounted<T, DefaultRefCountedTraits>::DeleteInternal(x); } }; template <class T, typename Traits = DefaultRefCountedTraits<T>> //<--- DefaultRefCountedTraits class RefCounted : public subtle::RefCountedBase { ... }
而DefaultRefCountedTraits的工作很简单,直接delete:
friend struct DefaultRefCountedTraits<T>; template <typename U> static void DeleteInternal(const U* x) { delete x; }
当然,它也支持自定义清理类,比如我们举例的RefcountedKeyedService使用了RefcountedKeyedServiceTraits,它是自定义删除类。阅读RefcountedKeyedServiceTraits::Destruct可以得知它的实现如下,一样,直接delete obj,不会清空指针为nullptr。
struct KEYED_SERVICE_EXPORT RefcountedKeyedServiceTraits { static void Destruct(const RefcountedKeyedService* obj); }; void RefcountedKeyedServiceTraits::Destruct(const RefcountedKeyedService* obj) { if (obj->task_runner_ && !obj->task_runner_->RunsTasksInCurrentSequence()) { obj->task_runner_->DeleteSoon(FROM_HERE, obj); } else { delete obj; //<-------- } }