chromium中的智能指针
转载时请注明出处和作者联系方式: https://mogoweb.net(betway官网首页) betway官网首页@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中的智能指针(betway官网首页) @gmail.com