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

来源:互联网 发布:c语言如何清屏 编辑:程序博客网 时间:2024/05/18 00:45
       之前一直有用到智能指针,但一直没有真正去了解其内部的实现,并且之前用到的很多智能指针实现方式是经过封装过的,如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使用实例如下:
    #include <boost/scoped_ptr.hpp>    #include <iostream>    struct Shoe { ~Shoe() { std::cout << "Buckle my shoe\n"; } };    class MyClass {        boost::scoped_ptr<int> ptr;      public:        MyClass() : ptr(new int) { *ptr = 0; }        int add_one() { return ++*ptr; }    };    int main()    {        boost::scoped_ptr<Shoe> x(new Shoe);        MyClass my_instance;        std::cout << my_instance.add_one() << '\n';        std::cout << my_instance.add_one() << '\n';    }

       程序执行后的结果:
       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来打破这个循环。
       使用实例:
void f(shared_ptr<int>, int);int g();void ok(){    shared_ptr<int> p(new int(2));    f(p, g());}
    
       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使用实例:
shared_ptr<int> p(new int(5));weak_ptr<int> q(p);// some time laterif(shared_ptr<int> r = q.lock()){    // use *r}

       了解了boost中的只能指针后,在来了解一写关于chromium中WeakPtr的知识:
       首先我们需要了解一下WeakPtr为什么会出现。从Chrome源码剖析这篇文章中我们可以了解到chromium的代码中会尽量避免用锁来处理多线程的问题,而换用task的机制来完成多线程的实现。但使用task机制来处理多线程的时候经常会碰到这么个问题,就是当多个task共用一个对象是,我们该如何管理这个对象的生命周期,WeakPtr正是为了处理这个问题而出现的。关于WeakPtr如何解决上述的问题我们可以在《浅谈chromium中的指针管理》中进一步的了解,这篇文章介绍的相对比较详细。
       通过上面的了解,总体上来说,chromium中的WeakPtr与boost中的weak_ptr虽然都叫弱指针,但它们所要描述的东西却完全不一样,实现方式也完全不一样,要注意区分。
       另外,在chromium的文档中还这么描述了WeakPtr。弱指针主要是使用在那些拥有多个引用计数,并且不希望自己的生命周期与这些引用计数绑定在一起的对象上。
       下面有这么一段示例代码:
  class Controller : public SupportsWeakPtr<Controller> {   public:    void SpawnWorker() { Worker::StartNew(AsWeakPtr()); }    void WorkComplete(const Result& result) { ... }  };  class Worker {   public:    static void StartNew(const WeakPtr<Controller>& controller) {      Worker* worker = new Worker(controller);      // Kick off asynchronous processing...    }   private:    Worker(const WeakPtr<Controller>& controller)        : controller_(controller) {}    void DidCompleteAsynchronousProcessing(const Result& result) {      if (controller_)        controller_->WorkComplete(result);    }    WeakPtr<Controller> controller_;};

       在这个示例中,用户可能会动态分配一个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

原创粉丝点击