zoukankan      html  css  js  c++  java
  • shared_ptr & weak_ptr

    shared_ptr

    <1> 类模板说明

      1 namespace boost
      2 {
      3     class bad_weak_ptr: public std::exception;
      4     template<class T> class weak_ptr;
      5     template<class T> class shared_ptr
      6     {
      7     public:
      8         typedef T element_type;
      9 1.1 构造与析构
     10 /* 1.1.1 默认构造 */
     11         说明:构造一个空的shared_ptr
     12         结果:use_count() == 0 && get() == 0
     13         shared_ptr(); // never throws
     14         shared_ptr(std::nullptr_t); // never throws
     15 /* 1.1.2 指针构造 */
     16         说明:Y必须是一个完整的类型,Y*应该可以转换为T*。p必须是通过new分配的指针或者0。
     17         结果:use_count() == 1 && get() == p
     18         template<class Y> explicit shared_ptr(Y * p);
     19 /* 1.1.3 带有析构器的构造 */
     20         说明:构造一个包含指针p和析构器d的shared_ptr。
     21         结果:use_count() == 1 && get() == p
     22         template<class Y, class D> shared_ptr(Y * p, D d);
     23         template<class Y, class D, class A> shared_ptr(Y * p, D d, A a);
     24         template<class D> shared_ptr(std::nullptr_t p, D d);
     25               template<class D, class A> shared_ptr(std::nullptr_t p, D d, A a);
     26 /* 1.1.4 复制和转换构造 */
     27         说明:Y*应该可以转换为T*。如果r为空,则构造一个空的shared_ptr;否则构造一个与r同样拥有权的shared_ptr
     28         结果:use_count() == r.use_count() && get() == r.get()
     29               shared_ptr(shared_ptr const & r); // never throws
     30               template<class Y> shared_ptr(shared_ptr<Y> const & r); // never throws
     31 /* 1.1.5 移动构造 */
     32         说明:Y*应该可以转换为T* 33         结果:*this包含r中的旧值,r == 0 && r.get() == 0
     34               shared_ptr(shared_ptr && r); // never throws
     35               template<class Y> shared_ptr(shared_ptr<Y> && r); // never throws
     36 /* 1.1.6 别名构造 */
     37         说明:构造一个shared_ptr,与r同样的拥有权,并且包含p
     38         结果:use_count() == r.use_count() && get() == p
     39               template<class Y> shared_ptr(shared_ptr<Y> const & r, element_type * p); // never throws
     40 /* 1.1.7 weak_ptr构造 */
     41         说明:Y*应该可以转换为T*。构造一个shared_ptr,与r同样的拥有权,并且包含一个r中指针的副本
     42         结果:use_count() == r.use_count()
     43               template<class Y> explicit shared_ptr(weak_ptr<Y> const & r);
     44 /* 1.1.8 auto_ptr构造 */
     45         说明:Y*应该可以转换为T* 46         结果:use_count() == 1
     47               template<class Y> explicit shared_ptr(std::auto_ptr<Y> & r);
     48               template<class Y> shared_ptr(std::auto_ptr<Y> && r);
     49 /* 1.1.9 unique_ptr构造 */
     50         说明:Y*应该可以转换为T*。等价于shared_ptr(r.release(), r.get_deleter())
     51         结果:use_count() == 1
     52               template<class Y, class D> shared_ptr(std::unique_ptr<Y, D> && r);
     53 /* 1.1.10 析构函数 */
     54         说明:
     55             如果*this为空,或者拥有其他shared_ptr实例的控制权(use_count() > 1),那么什么都不做;
     56             如果*this拥有一个指针p和一个析构器d,那么调用d(p);
     57             如果*this拥有一个指针p,那么调用delete p。
     58         ~shared_ptr(); // never throws
     59 1.2 赋值操作符
     60         说明:等价于shared_ptr(r).swap(*this),返回*this 61               shared_ptr & operator=(shared_ptr const & r); // never throws
     62               template<class Y> shared_ptr & operator=(shared_ptr<Y> const & r); // never throws
     63         template<class Y> shared_ptr & operator=(std::auto_ptr<Y> & r);
     64 
     65         说明:等价于shared_ptr(std::move(r)).swap(*this),返回*this 66               shared_ptr & operator=(shared_ptr const && r); // never throws
     67               template<class Y> shared_ptr & operator=(shared_ptr<Y> const && r); // never throws
     68               template<class Y> shared_ptr & operator=(std::auto_ptr<Y> && r);
     69               template<class Y, class D> shared_ptr & operator=(std::unique_ptr<Y, D> && r);
     70         说明:等价于shared_ptr().swap(*this),返回*this 71               shared_ptr & operator=(std::nullptr_t); // never throws
     72 1.3 重置操作
     73         说明:等价于shared_ptr().swap(*this)。
     74               void reset(); // never throws
     75         说明:等价于shared_ptr(p).swap(*this)。
     76               template<class Y> void reset(Y * p);
     77         说明:等价于shared_ptr(p, d).swap(*this)。
     78               template<class Y, class D> void reset(Y * p, D d);
     79         说明:等价于shared_ptr(p, d, a).swap(*this)。
     80               template<class Y, class D, class A> void reset(Y * p, D d, A a);
     81         说明:等价于shared_ptr(r, p).swap(*this)。
     82               template<class Y> void reset(shared_ptr<Y> const & r, element_type * p); // never throws
     83 1.4 间接操作
     84               T & operator*() const; // never throws; only valid when T is not an array type
     85               T * operator->() const; // never throws; only valid when T is not an array type
     86 
     87               element_type & operator[](std::ptrdiff_t i) const; // never throws; only valid when T is an array type
     88 1.5 逻辑运算
     89         说明:如果a.get() == b.get(),则返回true。
     90         template<class T, class U>
     91             bool operator==(shared_ptr<T> const & a, shared_ptr<U> const & b); // never throws
     92         说明:如果a.get() != b.get(),则返回true。
     93           template<class T, class U>
     94             bool operator!=(shared_ptr<T> const & a, shared_ptr<U> const & b); // never throws
     95 
     96           template<class T, class U>
     97             bool operator<(shared_ptr<T> const & a, shared_ptr<U> const & b); // never throws
     98         说明:如果p.get() == 0,则返回true。
     99           template<class T>
    100             bool operator==(shared_ptr<T> const & p, std::nullptr_t); // never throws
    101           template<class T>
    102             bool operator==(std::nullptr_t, shared_ptr<T> const & p); // never throws
    103         说明:如果p.get() != 0,则返回true。
    104           template<class T>
    105             bool operator!=(shared_ptr<T> const & p, std::nullptr_t); // never throws
    106           template<class T>
    107             bool operator!=(std::nullptr_t, shared_ptr<T> const & p); // never throws
    108 1.6 其他操作
    109         说明:返回原始指针。
    110             element_type * get() const; // never throws
    111         说明:如果use_count() == 1,则返回true,效率比use_count()高。
    112             bool unique() const; // never throws
    113         说明:返回shared_ptr的引用计数。
    114             long use_count() const; // never throws
    115             explicit operator bool() const; // never throws
    116         说明:交换两个智能指针的内容。
    117             void swap(shared_ptr & b); // never throws
    118 
    119             template<class Y> bool owner_before(shared_ptr<Y> const & rhs) const; // never throws
    120             template<class Y> bool owner_before(weak_ptr<Y> const & rhs) const; // never throws
    121       };
    122 
    123     说明:等价于a.swap(b)。
    124       template<class T> void swap(shared_ptr<T> & a, shared_ptr<T> & b); // never throws
    125     说明:返回p.get()。
    126       template<class T> typename shared_ptr<T>::element_type * get_pointer(shared_ptr<T> const & p); // never throws
    127     说明:几种转换操作。
    128       template<class T, class U>
    129         shared_ptr<T> static_pointer_cast(shared_ptr<U> const & r); // never throws
    130       template<class T, class U>
    131         shared_ptr<T> const_pointer_cast(shared_ptr<U> const & r); // never throws
    132       template<class T, class U>
    133         shared_ptr<T> dynamic_pointer_cast(shared_ptr<U> const & r); // never throws
    134       template<class T, class U>
    135         shared_ptr<T> reinterpet_pointer_cast(shared_ptr<U> const & r); // never throws
    136     说明:执行os << p.get(),返回os。
    137       template<class E, class T, class Y>
    138         std::basic_ostream<E, T> & operator<< (std::basic_ostream<E, T> & os, shared_ptr<Y> const & p);
    139     说明:返回者p对应的析构器d或者0。
    140       template<class D, class T>
    141       D * get_deleter(shared_ptr<T> const & p);
    142 }
    View Code

    <2> 示例用法

    示例 [1]:(基本用法)

     1 // shared_ptr1.cc
     2 #include <vector>
     3 #include <set>
     4 #include <iostream>
     5 #include <algorithm>
     6 #include <boost/shared_ptr.hpp>
     7 
     8 //  The application will produce a series of
     9 //  objects of type Foo which later must be
    10 //  accessed both by occurrence (std::vector)
    11 //  and by ordering relationship (std::set).
    12 
    13 struct Foo
    14 {
    15   Foo( int _x ) : x(_x) {}
    16   ~Foo() { std::cout << "Destructing a Foo with x=" << x << "
    "; }
    17   int x;
    18   /* ... */
    19 };
    20 
    21 typedef boost::shared_ptr<Foo> FooPtr;
    22 
    23 struct FooPtrOps
    24 {
    25   bool operator()( const FooPtr & a, const FooPtr & b )
    26     { return a->x > b->x; }
    27   void operator()( const FooPtr & a )
    28     { std::cout << a->x << "
    "; }
    29 };
    30 
    31 int main()
    32 {
    33   std::vector<FooPtr>         foo_vector;
    34   std::set<FooPtr,FooPtrOps>  foo_set; // NOT multiset!
    35 
    36   FooPtr foo_ptr( new Foo( 2 ) );
    37   foo_vector.push_back( foo_ptr );
    38   foo_set.insert( foo_ptr );
    39 
    40   foo_ptr.reset( new Foo( 1 ) );
    41   foo_vector.push_back( foo_ptr );
    42   foo_set.insert( foo_ptr );
    43 
    44   foo_ptr.reset( new Foo( 3 ) );
    45   foo_vector.push_back( foo_ptr );
    46   foo_set.insert( foo_ptr );
    47 
    48   foo_ptr.reset ( new Foo( 2 ) );
    49   foo_vector.push_back( foo_ptr );
    50   foo_set.insert( foo_ptr );
    51 
    52   std::cout << "foo_vector:
    ";
    53   std::for_each( foo_vector.begin(), foo_vector.end(), FooPtrOps() );
    54 
    55   std::cout << "
    foo_set:
    ";
    56   std::for_each( foo_set.begin(), foo_set.end(), FooPtrOps() );
    57   std::cout << "
    " << "the program is done..." << "
    
    ";
    58 }
    59 
    60 // output
    61 foo_vector:
    62 2
    63 1
    64 3
    65 2
    66 
    67 foo_set:
    68 3
    69 2
    70 1
    71 
    72 the program is done...
    73 
    74 Destructing a Foo with x=2
    75 Destructing a Foo with x=1
    76 Destructing a Foo with x=3
    77 Destructing a Foo with x=2
    View Code

    示例 [2]:(惯用法)使用shared_ptr来隐藏不完整类型的实现细节。

     1 // shared_ptr2.hpp
     2 #include <boost/shared_ptr.hpp>
     3 
     4 //  This example demonstrates the handle/body idiom (also called pimpl and
     5 //  several other names).  It separates the interface (in this header file)
     6 //  from the implementation (in shared_ptr_example2.cpp).
     7 
     8 //  Note that even though example::implementation is an incomplete type in
     9 //  some translation units using this header, shared_ptr< implementation >
    10 //  is still valid because the type is complete where it counts - in the
    11 //  shared_ptr_example2.cpp translation unit where functions requiring a
    12 //  complete type are actually instantiated.
    13 
    14 class example
    15 {
    16 public:
    17   example();
    18   void do_something();
    19 private:
    20   class implementation;
    21   boost::shared_ptr< implementation > _imp; // hide implementation details
    22 };
    23 
    24 // shared_ptr2.cc
    25 #include "shared_ptr2.hpp"
    26 #include <iostream>
    27 
    28 class example::implementation
    29 {
    30  public:
    31   ~implementation() { std::cout << "destroying implementation
    "; }
    32 };
    33 
    34 example::example() : _imp( new implementation ) {}
    35 
    36 void example::do_something()
    37   { std::cout << "use_count() is " << _imp.use_count() << "
    "; }
    38 
    39 // shared_ptr2_test.cc
    40 #include "shared_ptr2.hpp"
    41 
    42 int main()
    43 {
    44   example a;
    45   a.do_something();
    46   example b(a);
    47   b.do_something();
    48   example c;
    49   c = a;
    50   c.do_something();
    51   return 0;
    52 }
    53 
    54 // output
    55 use_count() is 1
    56 use_count() is 2
    57 destroying implementation
    58 use_count() is 3
    59 destroying implementation
    View Code

    示例 [3]:(线程安全性)一个shared_ptr实例可以同时被多个线程<read>(使用const操作访问);不同shared_ptr实例可以同时被多个线程<write>(使用mutable操作访问,例如operator=、reset);如果多个线程需要同时写同一个shared_ptr实例,则需要加锁保护。

     1 shared_ptr<int> p(new int(42));
     2 
     3 //--- Example 1 ---
     4 // thread A
     5 shared_ptr<int> p2(p); // reads p
     6 // thread B
     7 shared_ptr<int> p3(p); // OK, multiple reads are safe
     8 
     9 //--- Example 2 ---
    10 // thread A
    11 p.reset(new int(1912)); // writes p
    12 // thread B
    13 p2.reset(); // OK, writes p2
    14 
    15 //--- Example 3 ---
    16 // thread A
    17 p = p3; // reads p3, writes p
    18 // thread B
    19 p3.reset(); // writes p3; undefined, simultaneous read/write
    20 
    21 //--- Example 4 ---
    22 // thread A
    23 p3 = p2; // reads p2, writes p3
    24 // thread B
    25 // p2 goes out of scope: undefined, the destructor is considered a "write access"
    26 
    27 //--- Example 5 ---
    28 // thread A
    29 p3.reset(new int(1));
    30 // thread B
    31 p3.reset(new int(2)); // undefined, multiple writes
    View Code

    weak_ptr

    <1> 类模板说明

     1 namespace boost 
     2 {
     3 template<class T> class weak_ptr 
     4 {
     5 public:
     6         typedef T element_type;
     7     说明:构造一个空的weak_ptr,使得use_count() == 0
     8         weak_ptr();
     9     说明:use_count() == r.use_count()
    10           template<class Y> weak_ptr(shared_ptr<Y> const & r);
    11           weak_ptr(weak_ptr const & r);
    12           template<class Y> weak_ptr(weak_ptr<Y> const & r);
    13 
    14           ~weak_ptr();
    15     说明:等价于weak_ptr(r).swap(*this)。
    16           weak_ptr & operator=(weak_ptr const & r);
    17           template<class Y> weak_ptr & operator=(weak_ptr<Y> const & r);
    18           template<class Y> weak_ptr & operator=(shared_ptr<Y> const & r);
    19     说明:如果*this为空,返回0;否则返回shared_ptr对象中的引用计数。
    20           long use_count() const;
    21     说明:如果use_count() == 0,返回true。
    22           bool expired() const;
    23     说明:返回expired()? shared_ptr<T>(): shared_ptr<T>(*this)。
    24           shared_ptr<T> lock() const;
    25     说明:等价于weak_ptr().swap(*this)。
    26           void reset();
    27           void swap(weak_ptr<T> & b);
    28       };
    29 
    30       template<class T, class U>
    31         bool operator<(weak_ptr<T> const & a, weak_ptr<U> const & b);
    32 
    33       template<class T>
    34         void swap(weak_ptr<T> & a, weak_ptr<T> & b);
    35 }
    36     
    View Code

    总结

    <1> 关于shared_ptr:

    shared_ptr类模板用于管理一个动态分配对象的指针(典型地,通过C++中的new表达式)。当所指对象的引用计数为0时,自动调用所指对象的析构函数。在调用析构函数时,是根据构造shared_ptr时传入的指针类型,而非模板参数,如:

    shared_ptr<void> p(new int(5));  析构时调用int*类型的析构函数,而非void*类型。

    从boost 1.53开始,shared_ptr可以被用来管理动态分配的数组的指针,传入模板参数是可以指定数组的大小,也可以不指定,没什么太大的区别,如下:

    shared_ptr<double[1024]> p1(new double[1024]);

    shared_ptr<double []> p2(new double[1024]);

    由于使用了引用计数,那么可能会造成循环引用的问题。如下为示例程序:

     1 // shared_ptr3_cycles.cc
     2 #include <iostream>
     3 #include <memory>
     4 #include <string>
     5 #include <vector>
     6 #include <algorithm>
     7 
     8 using namespace std;
     9 
    10 class Controller
    11 {
    12 public:
    13     explicit Controller(int i) : num(i) ,status("On")
    14     {
    15         cout << "Creating Controller" << num << endl;
    16     }
    17 
    18     ~Controller()
    19     {
    20         cout << "Destroying Controller" << num << endl;
    21     }
    22 
    23     // Demonstrates how to test whether the pointed-to memory still exists or not.
    24     void checkStatuses() const
    25     {
    26         for_each
    27         (others.begin(), others.end(),
    28                  [](weak_ptr<Controller> wp)
    29                     {
    30                         try
    31                         {
    32                             auto p = wp.lock();
    33                             cout << "status of " << p->num << " = " << p->status << endl;
    34                         }
    35                         catch (bad_weak_ptr b)
    36                         {
    37                             cout << "null object" << endl;
    38                         }
    39                     }
    40         );
    41     }
    42 
    43     int num;
    44     string status;
    45     vector<shared_ptr<Controller> > others;
    46     //vector<weak_ptr<Controller> > others;     // 使用weak_ptr避免循环引用
    47                                                 // Controller 对象表示设备控制器
    48                                                 // 由于每个控制器必须能够在任何时间查询其他控制器的状态,因此包含 vector<weak_ptr<Controller> >
    49 };
    50 
    51 void RunTest()
    52 {
    53     vector<shared_ptr<Controller> > v;
    54 
    55     v.push_back(shared_ptr<Controller>(new Controller(1)));
    56     v.push_back(shared_ptr<Controller>(new Controller(2)));
    57     v.push_back(shared_ptr<Controller>(new Controller(3)));
    58 
    59     // Each controller depends on all others not being deleted.
    60     // Give each controller a pointer to all the others.
    61     for (int i = 0 ; i < v.size(); ++i)
    62     {
    63         for_each
    64         (v.begin(), v.end(),
    65             [v,i](shared_ptr<Controller> p)
    66             {
    67                 if(p->num != i)
    68                 {
    69                     v[i]->others.push_back(shared_ptr<Controller>(p));
    70                     // v[i]->others.push_back(weak_ptr<Controller>(p));
    71                     cout << "push_back to v[" << i << "]: " << p->num << endl;
    72                 }
    73             }
    74         );
    75     }
    76 
    77     for_each
    78     (v.begin(), v.end(),
    79         [](shared_ptr<Controller>& p)
    80         {
    81             cout << "use_count = " << p.use_count() << endl;
    82             p->checkStatuses();
    83         }
    84     );
    85 }
    86 
    87 int main()
    88 {
    89     RunTest();
    90     return 0;
    91 }
    View Code

    上述程序运行结果如下:

     1 // output
     2 Creating Controller1
     3 Creating Controller2
     4 Creating Controller3
     5 push_back to v[0]: 1
     6 push_back to v[0]: 2
     7 push_back to v[0]: 3
     8 push_back to v[1]: 2
     9 push_back to v[1]: 3
    10 push_back to v[2]: 1
    11 push_back to v[2]: 3
    12 use_count = 3
    13 status of 1 = On
    14 status of 2 = On
    15 status of 3 = On
    16 use_count = 3
    17 status of 2 = On
    18 status of 3 = On
    19 use_count = 4
    20 status of 1 = On
    21 status of 3 = On

    可以发现,上述程序由于出现了循环引用问题,导致析构函数没有调用,如果程序中使用vector<weak_ptr<Controller> > others记录其他控制器的状态,由于不涉及引用计数的增加,因此use_count函数永远返回1,这样就打破了循环引用,只需修改上述程序中注释掉的两行即可,修改后运行结果如下:

     1 Creating Controller3
     2 push_back to v[0]: 1
     3 push_back to v[0]: 2
     4 push_back to v[0]: 3
     5 push_back to v[1]: 2
     6 push_back to v[1]: 3
     7 push_back to v[2]: 1
     8 push_back to v[2]: 3
     9 use_count = 1
    10 status of 1 = On
    11 status of 2 = On
    12 status of 3 = On
    13 use_count = 1
    14 status of 2 = On
    15 status of 3 = On
    16 use_count = 1
    17 status of 1 = On
    18 status of 3 = On
    19 Destroying Controller1
    20 Destroying Controller2
    21 Destroying Controller3

    <2> 关于weak_ptr:

    weak_ptr类模板存储一个shared_ptr管理的对象的<弱引用>,即可以访问shared_ptr拥有的对象,但是不参与引用计数。如果程序中需要观察某个对象的状态,最好使用weak_ptr。同时weak_ptr也可以断开shared_ptr对象之间的循环引用。为了访问这个对象,可以使用shared_ptr构造函数将weak_ptr转换为一个shared_ptr(也可以使用weak_ptr的成员函数lock来转换)。如果shared_ptr管理的对象已经被析构,此时使用转换操作,那么shared_ptr的转换构造将抛出boost::bad_weak_ptr异常,而weak_ptr::lock将返回一个空的shared_ptr。

    与shared_ptr相比,weak_ptr提供了非常有限的操作,因为在多线程程序中操作weak_ptr比较危险。shared_ptr中有一个get函数用于返回一个原始指针,如下是一种错误的用法:

    shared_ptr<int> p(new int(5));

    weak_ptr<int> q(p);

    // ...

    if (int* r = q.get())

    {

        // use *r

    }

    如果在if语句后,使用r前,有另一个线程执行了:p.reset(),那么r就变为了空悬指针(dangling pointer),解决方法是利用weak_ptr中的lock函数创建一个q的临时shared_ptr:

    shared_ptr<int> p(new int(5));

    weak_ptr<int> q(p);

    // ...

    if (shared_ptr<int> r = q.lock())

    {

        // use *r

    }



  • 相关阅读:
    一个基于STM32F429 HAL库的学习工程模板
    STM32F4 SPI 学习笔记
    STM32 相同头文件名称的路径问题
    STM32F429基于CUBEMX的串口中断接收
    STM32F429 使用ESP8266通讯心得
    Zabbix 配置通过sendEmail发送邮件报警
    CentOS 7 下安装Zabbix 3.0
    centOS 6.5下Zabbix RPM安装
    Java安装和配置(jdk)
    centos7.2 系统基础优化
  • 原文地址:https://www.cnblogs.com/benxintuzi/p/4859300.html
Copyright © 2011-2022 走看看