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

来源:互联网 发布:xilinx ise mac 编辑:程序博客网 时间:2024/05/19 16:34

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设计中令人诟病的拷贝复制时被管理的对象转移的问题。简单的禁用拷贝和复制函数就可以达到此效果。所以它们的使用场合就非常明确和简单有限:

//   {//     scoped_ptr<Foo> foo;          // No pointer managed.//     foo.reset(new Foo("wee"));    // Now a pointer is managed.//     foo.reset(new Foo("wee2"));   // Foo("wee") was destroyed.//     foo.reset(new Foo("wee3"));   // Foo("wee2") was destroyed.//     foo->Method();                // Foo::Method() called.//     foo.get()->Method();          // Foo::Method() called.//     SomeFunc(foo.Release());      // SomeFunc takes owernship, foo no longer//                                   // manages a pointer.//     foo.reset(new Foo("wee4"));   // foo manages a pointer again.//     foo.reset();                  // Foo("wee4") destroyed, foo no longer//                                   // manages a pointer.//   }  // foo wasn't managing a pointer, so nothing was destroyed.
同时它们也禁止了两个智能指针之间的比,较,因为它们都不允许一个对象同时被2个智能指针同时管理:

private:  // Forbid comparison of scoped_ptr types.  If C2 != C, it totally doesn't  // make sense, and if C2 == C, it still doesn't make sense because you should  // never have the same object owned by two different scoped_ptrs.  template <class C2> bool operator==(scoped_ptr<C2> const& p2) const;  template <class C2> bool operator!=(scoped_ptr<C2> const& p2) const;

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

  ~scoped_ptr() {    enum { type_must_be_complete = sizeof(C) };    delete ptr_;  }
所以,编译这些模板类时,必须知道管理对象的定义。也就是说被管理对象的定义须在这些模板类定义之前给出。


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模板类:

template <class T>class scoped_refptr { public:  scoped_refptr() : ptr_(NULL) {  }  scoped_refptr(T* p) : ptr_(p) {    if (ptr_)      ptr_->AddRef();  }  scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {    if (ptr_)      ptr_->AddRef();  }  ~scoped_refptr() {    if (ptr_)      ptr_->Release();  }  T* get() const { return ptr_; }  operator T*() const { return ptr_; }  T* operator->() const { return ptr_; }  scoped_refptr<T>& operator=(T* p) {    // AddRef first so that self assignment should work    if (p)      p->AddRef();    if (ptr_ )      ptr_ ->Release();    ptr_ = p;    return *this;  }  scoped_refptr<T>& operator=(const scoped_refptr<T>& r) {    return *this = r.ptr_;  }  void swap(T** pp) {    T* p = ptr_;    ptr_ = *pp;    *pp = p;  }  void swap(scoped_refptr<T>& r) {    swap(&r.ptr_);  } protected:  T* ptr_;};

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

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

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

int* pa = new int(3);{    boost::shared_ptr<int> psa(pa);    ...    boost::shared_ptr<int> psb(pa);}
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技术。







原创粉丝点击