首页 > chromium研究 > chromium中的智能指针

chromium中的智能指针

2012年9月18日 发表评论 阅读评论

转载时请注明出处和作者联系方式: http://mogoweb.net mogoweb@gmail.com

C/C++程序员最不愿意面对但又必须面对的就是指针引起的内存问题。围绕指针问题也有很多解决方案,比如android中的strong pointer/weak pointer,WebKit中的RefPtr和PassRefPtr,C++标准库中的auto_ptr,等等。毫不意外,chromium也有自己的指针管理类(看来还是自己发明的轮子用起来顺手一些):scoped_ptr/scoped_array和scoped_refptr。

scoped_ptr/scoped_array

顾名思义,模板类scoped_ptr用于管理指针拥有权,在离开作用域后自动delete指针。scoped_array则用于数组的管理。scoped_ptr和scoped_array分别对应着new/delete和new[]/delete[]。首先我们来看看scoped_ptr的用法:

{

  scoped_ptr<Foo> foo(new Foo(“wee”));

} // foo离开生命周期,释放所拥有的指针

{

  scoped_ptr<Foo> foo;           // 没有管理指针

  foo.reset(new Foo(“wee”));   // 现在管理了指针

  foo.reset(new Foo(“wee2”)); // Foo(“wee”)被销毁

  foo.reset(new Foo(“wee3”)); // Foo(“wee2”)被销毁

  foo->Method();                      // 调用Foo::Method()

  foo.get()->Method();             // 调用Foo::Method()

  SomeFunc(foo.release());      // SomeFunc获得所有权,foo不再管理指针

  foo.reset(new Foo(“wee4”));// foo又管理指针

  foo.reset();                           // Foo(“wee4”)销毁,foo不再管理指针

} // foo没有管理指针,所以没有指针需要销毁

scoped_ptr还实现了C++11 unique_ptr的部分功能,所以它能转移所有权,但不能复制。所以如下代码是错误的:


{

  scoped_ptr<Foo> foo(new Foo(“wee”));

  scoped_ptr<Foo> other = foo;  // 错误,scoped_ptr不能复制

scoped_ptr不能复制,是否意味着scoped_ptr不能作为函数参数和函数返回值呢?答案是可以,不过在使用时需要改变一下写法,下面是scoped_ptr作为函数参数和返回值的例子:

void TakesOwnership(scoped_ptr<Foo> arg) {

}

scoped_ptr<Foo> CreateFoo() {

  return scoped_ptr<Foo>(new Foo(“new”));

}

scoped_ptr<Foo> PassThru(scoped_ptr<Foo> arg) {

  return arg.Pass();

}

{

  scoped_ptr<Foo> ptr(new Foo(“yay”));  // ptr管理Foo(“yay”)

  TakesOwnership(ptr.Pass());                  // ptr不再管理Foo(“yar”)

  scoped_ptr<Foo> ptr2 = CreateFoo();   // ptr2管理返回的Foo对象

  scoped_ptr<Foo> ptr3 = PassThru(ptr2.Pass()); // ptr3管理ptr2之前拥有的对象,ptr2不再管理任何对象

}

从上面的代码可以看出,在从函数返回scoped_ptr对象,或者调用带scoped_ptr参数的函数时,必须借助Pass()方法。CreateFoo有些特殊,因为在返回的代码行构造了一个临时对象,所以不需要调用Pass()方法。Pass()方法还可以正确的处理向上转型(upcast),例如:

scoped_ptr<Foo> foo(new Foo());

scoped_ptr<FooParent> parent = foo.Pass();

另外还有一个方法PassAs()用于在函数返回值进行向上转型。

scoped_ptr<Foo> CreateFoo() {

  scoped_ptr<FooChild> result(new FooChild());

  return result.PassAs<Foo>();

}

scoped_ptr模板类的优点是小、简单、效率高,但是存在一个缺点,不能共享所有权,如果多处需要同时持有某个指针对象,scoped_ptr就不能满足要求了。不过chromium中提供了另一个模板类scoped_refptr来弥补这一问题。

scoped_refptr

scoped_refptr是用于引用计数对象的智能指针类,使用该类后,无需手工调用引用计数对象的AddRef和Release方法,从而有效避免由于忘记调用Release引起内存泄漏。通常的用法如下:

class MyFoo : public RefCounted<MyFoo> {

   …

};

void some_function() {

  scoped_refptr<MyFoo> foo = new MyFoo();

  foo->Method(param);

  // foo在函数返回时自动释放

}

void some_other_function() {

  scoped_refptr<MyFoo> foo = new MyFoo();

  …

  foo = NULL; // 显式释放foo

  if (foo)

    foo->Method(param);

}

从上面的例子可以看到,使用scoped_refptr<T>就如同使用指向T的指针,只是不再担心指针的释放了。如果有两个scoped_refptr<T>对象,还可以交换彼此的引用,如下所示:

{

  scoped_refptr<MyFoo> a = new MyFoo();

  scoped_refptr<MyFoo> b;

  b.swap(a);

  // 现在b引用到MyFoo对象,而a则引用空指针

}

使用赋值语句,上面例子中的a和b可以引用到同一个MyFoo对象:

{

  scoped_refptr<MyFoo> a = new MyFoo();

  scoped_refptr<MyFoo> b;

  b = a;

  // 现在a和b都引用同一个MyFoo对象

}

需要注意的是,引用计数的功能并不是由scoped_refptr提供的,而是由scoped_refptr引用的对象本身提供的,也就说使用scoped_refptr的对象必须具备引用计数功能。Chromium中的引用计数功能由RefCouneted类提供。

转载时请注明出处和作者联系方式: chromium中的智能指针 mogoweb@gmail.com

分类: chromium研究 标签:
  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.