[Chrome源码阅读] 理解Chrome的smart pointer

Chrome代码中大量运用了智能指针来管理对象的指针,解决对象生命期的问题。这篇文章尝试着理解Chrome中定义的几个智能指针类。

1. scoped_ptr/scoped_array/scopred_array_malloc

以scopred开头的智能指针类定义在/src/base/scoped_ptr.h文件中。它们有着很明确的设计目标,对new/new[]/malloc出来的对象指针进行简单的包装,来管理对象的内存分配和释放。比如scoped_ptr类对new/delete进行了简单的包装,提供类似于std::auto_ptr类似的接口,但是却摒弃std::auto_ptr设计中令人诟病的拷贝复制时被管理的对象转移的问题。简单的禁用拷贝和复制函数就可以达到此效果。所以它们的使用场合就非常明确和简单有限:

[cpp]  view plain copy print ?
  1. //   {  
  2. //     scoped_ptr<Foo> foo;          // No pointer managed.  
  3. //     foo.reset(new Foo("wee"));    // Now a pointer is managed.  
  4. //     foo.reset(new Foo("wee2"));   // Foo("wee") was destroyed.  
  5. //     foo.reset(new Foo("wee3"));   // Foo("wee2") was destroyed.  
  6. //     foo->Method();                // Foo::Method() called.  
  7. //     foo.get()->Method();          // Foo::Method() called.  
  8. //     SomeFunc(foo.Release());      // SomeFunc takes owernship, foo no longer  
  9. //                                   // manages a pointer.  
  10. //     foo.reset(new Foo("wee4"));   // foo manages a pointer again.  
  11. //     foo.reset();                  // Foo("wee4") destroyed, foo no longer  
  12. //                                   // manages a pointer.  
  13. //   }  // foo wasn't managing a pointer, so nothing was destroyed.  
同时它们也禁止了两个智能指针之间的比,较,因为它们都不允许一个对象同时被2个智能指针同时管理:

[cpp]  view plain copy print ?
  1. private:  
  2.   // Forbid comparison of scoped_ptr types.  If C2 != C, it totally doesn't  
  3.   // make sense, and if C2 == C, it still doesn't make sense because you should  
  4.   // never have the same object owned by two different scoped_ptrs.  
  5.   template <class C2> bool operator==(scoped_ptr<C2> const& p2) const;  
  6.   template <class C2> bool operator!=(scoped_ptr<C2> const& p2) const;  


有一点需要注意的是,类中的很多函数用了编译器的检查机制:

[cpp]  view plain copy print ?
  1. ~scoped_ptr() {  
  2.   enum { type_must_be_complete = sizeof(C) };  
  3.   delete ptr_;  
  4. }  
所以,编译这些模板类时,必须知道管理对象的定义。也就是说被管理对象的定义须在这些模板类定义之前给出。


2. scoped_refptr/RefCounted<T>/RefCountedThreadSafe<T>

除了上面介绍的简单的智能指针之外,还有一个广泛使用的智能指针是针对智能指针的,类似于boost::shared_ptr类,它就是scoped_refptr。它管理的对象需继承于模板类RefCounted<T>,T就是自己本身。RefCounted<T>模板了提供了AddRef和Release函数(yy一下,为什么不叫IncRef和DecRef,意义不更明确吗?),同时还维护一个INT类型的引用计数。RefCountedThreadSafe<T>是线程安全的RefCounted版本,原因在于引用计数不是采用INT类型,而是一个AtomicRefCount类型(原子的)。

我们重点来关注下scoped_refptr模板类:

[cpp]  view plain copy print ?
  1. template <class T>  
  2. class scoped_refptr {  
  3.  public:  
  4.   scoped_refptr() : ptr_(NULL) {  
  5.   }  
  6.   
  7.   scoped_refptr(T* p) : ptr_(p) {  
  8.     if (ptr_)  
  9.       ptr_->AddRef();  
  10.   }  
  11.   
  12.   scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {  
  13.     if (ptr_)  
  14.       ptr_->AddRef();  
  15.   }  
  16.   
  17.   ~scoped_refptr() {  
  18.     if (ptr_)  
  19.       ptr_->Release();  
  20.   }  
  21.   
  22.   T* get() const { return ptr_; }  
  23.   operator T*() const { return ptr_; }  
  24.   T* operator->() const { return ptr_; }  
  25.   
  26.   scoped_refptr<T>& operator=(T* p) {  
  27.     // AddRef first so that self assignment should work  
  28.     if (p)  
  29.       p->AddRef();  
  30.     if (ptr_ )  
  31.       ptr_ ->Release();  
  32.     ptr_ = p;  
  33.     return *this;  
  34.   }  
  35.   
  36.   scoped_refptr<T>& operator=(const scoped_refptr<T>& r) {  
  37.     return *this = r.ptr_;  
  38.   }  
  39.   
  40.   void swap(T** pp) {  
  41.     T* p = ptr_;  
  42.     ptr_ = *pp;  
  43.     *pp = p;  
  44.   }  
  45.   
  46.   void swap(scoped_refptr<T>& r) {  
  47.     swap(&r.ptr_);  
  48.   }  
  49.   
  50.  protected:  
  51.   T* ptr_;  
  52. };  

scoped_refptr和boost::shared_ptr之间的区别:

boost::shared_ptr自己管理引用计数,每当它的拷贝构造和赋值运算符被调用时,这个引用计数加1。而scoped_refptr不管理引用计数,由对象自己管理。这样就带来下面不同的用法:

boost::shared_ptr的用例(不正确的):

[cpp]  view plain copy print ?
  1. int* pa = new int(3);  
  2. {  
  3.     boost::shared_ptr<int> psa(pa);  
  4.     ...  
  5.     boost::shared_ptr<int> psb(pa);  
  6. }  
psa/psb被销毁时都会尝试删除pa,结果导致double-delete问题出现。

如果换成scoped_ptr,那么就不会出现上述的问题。


关于智能指针的拥有权策略技术,共有deep copy, reference counting, reference linking和destructive copy。<Modern C++ Design>书籍第7章第5节详细讲到了这几种技术的优缺点,而且Loki库也提供这几种策略技术的实作版本。Chrome里面的智能指针和boost::shared_ptr都是采用reference counting技术。

你可能感兴趣的:([Chrome源码阅读] 理解Chrome的smart pointer)