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 }
<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
示例 [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
示例 [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
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
总结
<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 }
上述程序运行结果如下:
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
}