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 << "\n"; } 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 << "\n"; } 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:\n"; 53 std::for_each( foo_vector.begin(), foo_vector.end(), FooPtrOps() ); 54 55 std::cout << "\nfoo_set:\n"; 56 std::for_each( foo_set.begin(), foo_set.end(), FooPtrOps() ); 57 std::cout << "\n" << "the program is done..." << "\n\n"; 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\n"; } 32 }; 33 34 example::example() : _imp( new implementation ) {} 35 36 void example::do_something() 37 { std::cout << "use_count() is " << _imp.use_count() << "\n"; } 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
}