您的位置:首页 > 其它

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

2012-08-25 18:46 405 查看
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技术。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: