• 有关智能指针(shared_ptr)的讨论


    1. boost::shared_ptr的用法
    2. boost::shared_ptr的实现机制
    3. 使用boost::shared_ptr的注意事项
    4. std::tr1::shared_ptr和boost::shared_ptr
    5. 参考

    1. boost::shared_ptr的用法

     下面用一个简单的例子说明shared_ptr的用法:

    #include <stdio.h>
    #include <boost/shared_ptr.hpp>
    
    class A {
    public:
        void print() {
            printf("class A print!\n");
        }
    };
    
    int main(int argc, char **argv) {
        boost::shared_ptr<A> a1(new A());
        a1->print();
    }

    shared_ptr不用手动去释放资源,它会智能地在合适的时候去自动释放。如上面的例子,a1指向的对象将会在程序结束的时候自动释放(程序结束时所有申请的资源都会被释放,这只是为了说明其作用)。再来看下面的例子:

    //同上
    
    int main(int argc, char **argv) {
        boost::shared_ptr<A> a1(new A());
        a1->print();
        printf("a1 reference count: %d\n", a1.use_count());
        boost::shared_ptr<A> a2 = a1;
        printf("a1 reference count: %d\n", a1.use_count());
        printf("a2 reference count: %d\n", a2.use_count());
        a1.reset();
        printf("a2 reference count: %d\n", a2.use_count());
    }

    程序输出结果:

    class A print!
    a1 reference count: 1
    a1 reference count: 2
    a2 reference count: 2
    a2 reference count: 1

    上面调用了两上shared_ptr的成员方法,user_count()的作用是获得当前对象被引用的次数,reset()的作用是释放指针对对象的引用,将指针设为空。

    2. boost::shared_ptr的实现机制

     boost::shared_ptr的实现机制其实比较简单,就是对指针引用的对象进行引用计数,当有一个新的boost::shared_ptr指针指向一个对象时,就把该对象的引用计数加1,减少一个boost::shared_ptr指针指向一个对象时,就把对该对象的引用计数减1。当一个对象的引用计数变为0时,就会自动调用其析构函数或者free掉相应的空间。

    boost::shared_ptr的常用成员函数:

    (1) 构造一个空的指针

    shared_ptr(); // never throws
    shared_ptr(std::nullptr_t); // never throws
    template<class D> shared_ptr(std::nullptr_t p, D d);
    template<class D, class A> shared_ptr(std::nullptr_t p, D d, A a);

    上面几个函数可以初始化一个空的shared_ptr指针,其中,第三和第四个函数中的参数的意思是:d表示一个删除器(deleter),它会在释放资源的时候被调用,delete p会变成d(p)。a表示一个构造器,被用作分配空间。这两个接口允许调用者自己提供构造器和删除器,来自定义自己的构造和释放行为。

    (2) 根据变量构造指针 

    template<class Y> explicit shared_ptr(Y * p);
    template<class Y, class D> shared_ptr(Y * p, D d);
    template<class Y, class D, class A> shared_ptr(Y * p, D d, A a);

     这几个构造函数是通过一个Y类型的指针类型p来初始化shared_ptr指针,初始化后,指针会指针p所指的对象。其中,参数d和a的意义和上面相同。

    (3) 拷贝构造函数

    shared_ptr拥有常见的拷贝构造,移动构造函数,用法和普通构造函数一样,这里不做详述。还有一个比较特殊的构造函数:

    template<class Y> shared_ptr(shared_ptr<Y> const & r, element_type * p); // never throws

    这个函数的在boost的帮助文档中解释为:constructs a shared_ptr that shares ownership with r and stores p(构造一个shared_ptr对象存储p并且与r共享所有权),这个构造函数被称为aliasing constructor(不知道如何翻译,aliasing有重叠的意思)。r是将要共享所有权的指针,p是实际指向的对象,构造的指针调用get()或者operator->将返回p,而不是r。为了更好的理解这个函数,我们考虑shared_ptr指针对象由两个部分构成,一个是它的所有权(可以与其他指针共享的),另一个是它实际存储的对象。在普通应用中,这两部分是相同的。在由上述函数构造的shared_ptr中,两个部分是不同的。当一个指针的引用计数为0时,如果它还与其他指针共享所有权,那么它实际存储的对象不会被删除,直到共享的引用计数为0。下面的例子会更直观一些。

    struct data {...};
     
    struct object
    {
      data data_;
    };
     
    void f ()
    {
      shared_ptr<object> o (new object); // use_count == 1
      shared_ptr<data> d (o, &o->data_); // use_count == 2
     
      o.reset (); // use_count == 1
     
      // When d goes out of scope, object is deleted.
    }
     
    void g ()
    {
      typedef std::vector<object> objects;
     
      shared_ptr<objects> os (new objects); // use_count == 1
      os->push_back (object ());
      os->push_back (object ());
     
      shared_ptr<object> o1 (os, &os->at (0)); // use_count == 2
      shared_ptr<object> o2 (os, &os->at (1)); // use_count == 3
     
      os.reset (); // use_count == 2
     
      // When o1 goes out of scope, use_count becomes 1.
      // When o2 goes out of scope, objects is deleted.
    }

    关于这一函数的应用参考:http://codesynthesis.com/~boris/blog/2012/04/25/shared-ptr-aliasing-constructor/

    有关shared_ptr的其他成员函数参考:http://www.boost.org/doc/libs/1_53_0/libs/smart_ptr/shared_ptr.htm#functions

    3. 使用boost::shared_ptr的注意事项

     (1) 不要把一个原生指针给多个shared_ptr管理

    int* ptr = new int;
    boost::shared_ptr<int> p1(ptr);
    boost::shared_ptr<int> p2(ptr); 

    这样做会导致ptr会被释放两次。在实际应用中,保证除了第一个shared_ptr使用ptr定义之外,后面的都采用p1来操作,就不会出现此类问题。

     (2) 不要在函数实参里创建shared_ptr  

        function(shared_ptr<int>(new int), g());  //有缺陷
        //可能的过程是先new int,然后调g(),g()发生异常,shared_ptr<int>没有创建,int内存泄露
        //推荐写法
        shared_ptr<int> p(new int());
        f(p, g()); 

     (3) shared_ptr作为被保护的对象的成员时,小心因循环引用造成无法释放资源。

    简单的例子:  

    class parent;
    class children;
    typedef boost::shared_ptr<parent> parent_ptr;
    typedef boost::shared_ptr<children> children_ptr;
    
    class parent {
    public:
        children_ptr children;
    };
    
    class children {public:
        parent_ptr parent;
    };
    void test()
    {
        boost::shared_ptr<parent> father( new parent);
        boost::shared_ptr<children> son(new children);
        father->children = son;  //user_count() == 2
        son->parent = father;  //user_count() == 2
    }

    在这个例子中,出现了循环引用计数,赋值后use_count()变为2,出函数后变为1,资源无法被释放。boost的解决方法是采用weak_ptr来保存。

    class parent {public:
       boost::weak_ptr<children> children;
    };
    
    class children {public:
         boost::weak_ptr<father> parent;
    };

    因为boost不会影响weak_ptr不会影响引用计数,不会造成循环引用计数。

      (4) 不要把this指针给shared_ptr

    将this指针赋给shared_ptr会出现this指针被释放两次的危险,如下面的代码,会在t释放时析构一次,shared_ptr释放时析构一次。

    class test {
      public:
        boost::shared_ptr<test> pget() {
          return boost::shared_ptr<test>(this);
      }        
    };
    
    test t;
    boost::shared_ptr<test> pt = t.pget();

    boost库提供的解决方法是:使用enable_shared_from_this来实现。

    class test : public boost::enable_shared_from_this<test> {
      public:
        boost::shared_ptr<test> pget() {
          return shared_from_this();
      }        
    };
    
    test t;
    boost::shared_ptr<test> pt = t.pget();

    4. std::tr1::shared_ptr和boost::shared_ptr

      在新版本的C++标准中引用shared_ptr智能指针,名空间是std::tr1::shared_ptr。它和boost::shared_ptr的用法相同,在gcc4.3.x及以上的版本加选项-std=gnu++0x即可使用。

    参考:

    1. boost::shared_ptr参考:http://www.boost.org/doc/libs/1_53_0/libs/smart_ptr/shared_ptr.htm

    2. aliasing constructor函数原理及用法:http://codesynthesis.com/~boris/blog/2012/04/25/shared-ptr-aliasing-constructor/

    3. std::tr1::shared_ptr参考:http://www.cplusplus.com/reference/memory/shared_ptr/

    4. http://www.cnblogs.com/TianFang/archive/2008/09/19/1294521.html

  • 相关阅读:
    Selenium 2自动化测试实战
    Python学习笔记整理(python 3)
    Python编程中出现ImportError: bad magic number in 'numpy': b'x03xf3 '
    收集的一些表单常用的正则表达式。
    转载的一篇博客,感觉不错,自我感觉很到位,来自 http://www.cnblogs.com/laizhihui/p/5810965.html
    闲来无写的,就是中间有一条小细线,求大神指点。
    自己总结的有关PHP一些基本知识和一些常见的js问题
    不经意间看到的东西,感觉不错(转载)。
    无束缚版贪吃蛇(就问你爽不爽)
    小图局部放大效果(图片的话就自己找一个吧,记得是一张图片用两次,不是两张图片,而且你的图片不一定与我一样,需改一下放大的尺寸)
  • 原文地址:https://www.cnblogs.com/xiaoxinxd/p/shared_ptr_20130226.html
Copyright © 2020-2023  润新知