boost智能指针及chromium指针管理WeakPtr

转自 http://www.kaixinwenda.com/article-lisztlee-8303060.html 

之前一直有用到智能指针,但一直没有真正去了解其内部的实现,并且之前用到的很多智能指针实现方式是经过封装过的,如Comptr这类。今天在研究chromium中的代码是看到了其自定义的WeakPtr的实现,感觉自己对这部分知识不甚了解,趁着这个机会,好好把跟智能指针相关的知识理清楚。在这篇文章会重点讲讲boost标准库和chromium中一些定义及使用。

       首先,还是在boost中查看相关智能指针的实现,在C++中为了更好的管理内存,特别是管理那些动态分配且被多个对象拥有的对象,boost提出了一套智能指针(smart pointers)的标准。

       boost中提出了6种智能指针的使用方式,下面表格中的内容是从官方文档中抠出来的,可以事先做一个简单的了解。

scoped_ptr<boost/scoped_ptr.hpp>单个对象的唯一的一个拥有者,不可复制。
scoped_array<boost/scoped_array.hpp>数组对象的唯一的一个拥有者,不可复制。
shared_ptr<boost/shared_ptr.hpp>多个指针共享单个对象。
shared_array<boost/shared_array.hpp>

多个指针共享一个数组对象。

weak_ptr<boost/weak_ptr.hpp>一个被shared_ptr所拥有的对象的观察者(不拥有它)。
intrusive_ptr<boost/intrusive_ptr.hpp>内部嵌入一个引用计数来拥有一个共享对象。

        上述的6中智能指针都是std::auto_ptr模板的一个具体实现。

        1、scoped_ptr:

        scoped_ptr指向一个动态new出的对象,是一个相对简单的智能指针实现。当scoped_ptr自己被释放或者被手动执行reset的时候,它所指向的对象会被释放掉。这就是说,scoped_ptr所指向的对象只在当前作用域中有效。另外,由于它不可复制,所以当我们需要用到不用复制的对象时,使用scoped_ptr比使用shared_ptr或者std::auto_ptr更安全。

        scoped_ptr不能用在标准库的容器上。可用shared_ptr代替
       scoped_ptr 不能指向一块能够动态增长的内存区域。可用scoped_array代替。

       scoped_ptr使用实例如下:

[cpp]  view plain copy
  1. <span style="font-size:14px;">    #include <boost/scoped_ptr.hpp>  
  2.     #include <iostream>  
  3.   
  4.     struct Shoe { ~Shoe() { std::cout << "Buckle my shoe\n"; } };  
  5.   
  6.     class MyClass {  
  7.         boost::scoped_ptr<int> ptr;  
  8.       public:  
  9.         MyClass() : ptr(new int) { *ptr = 0; }  
  10.         int add_one() { return ++*ptr; }  
  11.     };  
  12.   
  13.     int main()  
  14.     {  
  15.         boost::scoped_ptr<Shoe> x(new Shoe);  
  16.         MyClass my_instance;  
  17.         std::cout << my_instance.add_one() << '\n';  
  18.         std::cout << my_instance.add_one() << '\n';  
  19.     }</span>  

       程序执行后的结果:
       1
       2
       Buckle my shoe


       2、scoped_array:

       它的实现方式很多和scoped_ptr一致,只是它管理的是一个数组对象,而不能管理单个对象。


       3、intrusive_ptr:

       intrusive_ptr的很多实现与share_ptr基本保持一致,但是它所管理的对象自己会维护一个引用计数。


       4、share_ptr:

       share_ptr指向一个动态new出的对象。当最后一个指向该对象的share_ptr被释放或者被手动执行reset的时候,所指向的对象会被释放掉。

       share_ptr能够用于C++标准库的容器上。同时,因为它能够执行比较操作,所以它也能在C++标准关系容器中使用。

       share_ptr的具体实现方式是采用引用计数的方式,所以当一个对象被循环引用的时候就会出现没法正常释放的情况,这是就要结合weak_ptr来打破这个循环。

       使用实例:

[cpp]  view plain copy
  1. <span style="font-size:14px;">void f(shared_ptr<int>, int);  
  2. int g();  
  3.   
  4. void ok()  
  5. {  
  6.     shared_ptr<int> p(new int(2));  
  7.     f(p, g());  
  8. }</span>  

     
       5、share_array:

       实现与share_ptr类似,只是它管理的是一个数组对象,而不能管理单个对象,这里不做过多介绍。


       6、weak_ptr:

       weak_ptr中存储着已经被share_ptr管理对象的一个弱引用,weak_ptr要想使用所指向的对象,需要通过share_ptr的构造函数或者lock成员函数转化为share_ptr。当一个对象的所有share_ptr都释放掉且该对象自己也被删除的时候,如果再尝试从一个指向已删除对象的weak_ptr中获取share_ptr则会失败。失败时构造函数会返回一个boost::bad_weak_ptr类型的异常,而weak_ptr::lock 则会返回一个空的shared_ptr。

       在share_ptr中有这么个构造函数定义:template<class Y> explicit shared_ptr(weak_ptr<Y> const & r);这个就是通过weak_ptr生成一个shared_ptr来访问该对象。

       weak_ptr的一个最大特点就是它共享一个share_ptr的内存,但是无论是构造还是析构一个weak_ptr 都不会影响引用计数器。

       weak_ptr使用实例:

[cpp]  view plain copy
  1. <span style="font-size:14px;">shared_ptr<int> p(new int(5));  
  2. weak_ptr<int> q(p);  
  3.   
  4. // some time later  
  5.   
  6. if(shared_ptr<int> r = q.lock())  
  7. {  
  8.     // use *r  
  9. }</span>  

       了解了boost中的只能指针后,在来了解一写关于chromium中WeakPtr的知识:

       首先我们需要了解一下WeakPtr为什么会出现。从Chrome源码剖析这篇文章中我们可以了解到chromium的代码中会尽量避免用锁来处理多线程的问题,而换用task的机制来完成多线程的实现。但使用task机制来处理多线程的时候经常会碰到这么个问题,就是当多个task共用一个对象是,我们该如何管理这个对象的生命周期,WeakPtr正是为了处理这个问题而出现的。关于WeakPtr如何解决上述的问题我们可以在《浅谈chromium中的指针管理》中进一步的了解,这篇文章介绍的相对比较详细。

       通过上面的了解,总体上来说,chromium中的WeakPtr与boost中的weak_ptr虽然都叫弱指针,但它们所要描述的东西却完全不一样,实现方式也完全不一样,要注意区分。

       另外,在chromium的文档中还这么描述了WeakPtr。弱指针主要是使用在那些拥有多个引用计数,并且不希望自己的生命周期与这些引用计数绑定在一起的对象上。

       下面有这么一段示例代码:

[cpp]  view plain copy
  1. <span style="font-size:14px;">  class Controller : public SupportsWeakPtr<Controller> {  
  2.    public:  
  3.     void SpawnWorker() { Worker::StartNew(AsWeakPtr()); }  
  4.     void WorkComplete(const Result& result) { ... }  
  5.   };  
  6.   
  7.   class Worker {  
  8.    public:  
  9.     static void StartNew(const WeakPtr<Controller>& controller) {  
  10.       Worker* worker = new Worker(controller);  
  11.       // Kick off asynchronous processing...  
  12.     }  
  13.    private:  
  14.     Worker(const WeakPtr<Controller>& controller)  
  15.         : controller_(controller) {}  
  16.     void DidCompleteAsynchronousProcessing(const Result& result) {  
  17.       if (controller_)  
  18.         controller_->WorkComplete(result);  
  19.     }  
  20.     WeakPtr<Controller> controller_;  
  21. };</span>  

       在这个示例中,用户可能会动态分配一个Controller的对象,之后再调用几次SpawnWorker,当所有的Works都完成后再销毁Controller,因为Worker中仅仅是维持一个Controller的弱指针,所以我们无需担心Worker在Controller释放后再对Controller解除引用。

     

       讲到这里,顺便插播个广告,google的code search着实很强大,在里面搜代码定位非常准确,感兴趣的话可以试试。

       此文讲述的还不够全面,还需进一步了解chromium中WeakPtr这个强大的实现方式。



参考文献:

boost smart pointers:

http://www.boost.org/doc/libs/1_52_0/libs/smart_ptr/smart_ptr.htm

Exception Safe Smart Pointers:

http://webcache.googleusercontent.com/search?q=cache:_n8cbXGp3ZoJ:www.open-std.org/jtc1/sc22/wg21/docs/papers/1994/N0555.ps+&cd=1&hl=zh-CN&ct=clnk&gl=cn

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值