boost::intrusive_ptr原理介紹

boost::intrusive_ptr一種「侵入式」的引用計數指針,它實際並不提供引用計數功能,而是要求被存儲的對象本身實現引用計數功能,並提供intrusive_ptr_add_ref和intrusive_ptr_release函數接口供boost::intrusive_ptr調用。html

下面經過一個具體的例子來講明boost::intrusive_ptr的用法,首先實現一個基類intrusive_ptr_base,定義intrusive_ptr_add_ref和intrusive_ptr_release函數來提供引用計數功能。ios

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/**
* intrusive_ptr_base基類,提供intrusive_ptr_add_ref()和intrusive_ptr_release()函數來提供引用計數功能;
* 使用boost::intrusive_ptr指針存儲的用戶類類型必須繼承自intrusive_ptr_base基類。
*/
#include <ostream>
#include <boost/checked_delete.hpp>
#include <boost/detail/atomic_count.hpp>
 
 
template < class  T>
class  intrusive_ptr_base {
public :
     /**
     * 缺省構造函數
     */
     intrusive_ptr_base(): ref_count(0) {
         std::cout << "  Default constructor "  << std::endl;
     }
     
     /**
     * 不容許拷貝構造,只能使用intrusive_ptr來構造另外一個intrusive_ptr
     */
     intrusive_ptr_base(intrusive_ptr_base<T> const &): ref_count(0) {
         std::cout << "  Copy constructor..."  << std::endl;
     }
     
     /**
     * 不容許進行賦值操做
     */
     intrusive_ptr_base& operator=(intrusive_ptr_base const & rhs) {
         std::cout << "  Assignment operator..."  << std::endl;
         return  * this ;
     }
     
     /**
     * 遞增引用計數(放到基類中以便compiler能找到,不然須要放到boost名字空間中)
     */
     friend  void  intrusive_ptr_add_ref(intrusive_ptr_base<T> const * s) {
         std::cout << "  intrusive_ptr_add_ref..."  << std::endl;
         assert (s->ref_count >= 0);
         assert (s != 0);
         ++s->ref_count;
     }
 
     /**
     * 遞減引用計數
     */
     friend  void  intrusive_ptr_release(intrusive_ptr_base<T> const * s) {
         std::cout << "  intrusive_ptr_release..."  << std::endl;
         assert (s->ref_count > 0);
         assert (s != 0);
         if  (--s->ref_count == 0)
             boost::checked_delete( static_cast <T const *>(s));  //s的實際類型就是T,intrusive_ptr_base<T>爲基類
     }
     
     /**
     * 相似於shared_from_this()函數
     */
     boost::intrusive_ptr<T> self() {
         return  boost::intrusive_ptr<T>((T*) this );
     }
     
     boost::intrusive_ptr< const  T> self() const  {
         return  boost::intrusive_ptr< const  T>((T const *) this );
     }
     
     int  refcount() const  {
         return  ref_count;
     }
     
private :
     ///should be modifiable even from const intrusive_ptr objects
     mutable  boost::detail::atomic_count ref_count;
 
};

用戶類類型須要繼承intrusive_ptr_base基類,以便具備引用計數功能。函數

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>
#include <string>
#include <boost/intrusive_ptr.hpp>
#include "intrusive_ptr_base.hpp"
 
/**
* 用戶類類型繼承自intrusive_ptr_base,該實現方式相似於boost::enable_shared_from_this<Y>
*/
class  Connection : public  intrusive_ptr_base< Connection > {
public :
     /**
     * 構造函數,調用intrusive_ptr_base< Connection >的缺省構造函數來初始化對象的基類部分
     */
     Connection( int  id, std::string tag):
         connection_id( id ), connection_tag( tag ) {}
 
     /**
     * 拷貝構造函數,只複製自身數據,不能複製引用計數部分
     */
     Connection( const  Connection& rhs):
         connection_id( rhs.connection_id ), connection_tag( rhs.connection_tag) {}
     
     /**
     * 賦值操做,一樣不能複製引用計數部分
     */
     const  Connection operator=( const  Connection& rhs) {
         if  ( this  != &rhs) {
             connection_id = rhs.connection_id;
             connection_tag = rhs.connection_tag;
         }
         
         return  * this ;
     }
 
private :
     int  connection_id;
     std::string connection_tag;
};
 
int  main() {
     std::cout << "Create an intrusive ptr"  << std::endl;
     boost::intrusive_ptr< Connection > con0 ( new  Connection(4, "sss" ) );  //調用intrusive_ptr_add_ref()遞增引用計數
     std::cout << "Create an intrusive ptr. Refcount = "  << con0->refcount() << std::endl;
 
     boost::intrusive_ptr< Connection > con1 (con0);   //調用intrusive_ptr_add_ref()
     std::cout << "Create an intrusive ptr. Refcount = "  << con1->refcount() << std::endl;
     boost::intrusive_ptr< Connection > con2 = con0;   //調用intrusive_ptr_add_ref()
     std::cout << "Create an intrusive ptr. Refcount = "  << con2->refcount() << std::endl;
     
     std::cout << "Destroy an intrusive ptr"  << std::endl;
 
     return  0;
}

程序運行輸出:this

Create an intrusive ptr
  Default constructor 
  intrusive_ptr_add_ref...
Create an intrusive ptr. Refcount = 1
  intrusive_ptr_add_ref...
Create an intrusive ptr. Refcount = 2
  intrusive_ptr_add_ref...
Create an intrusive ptr. Refcount = 3
Destroy an intrusive ptr
  intrusive_ptr_release...
  intrusive_ptr_release...
  intrusive_ptr_release...atom

對比boost::shared_ptrspa

使用boost::shared_ptr用戶類本省不須要具備引用計數功能,而是由boost::shared_ptr來提供;使用boost::shared_ptr的一大陷阱就是用一個raw pointer屢次建立boost::shared_ptr,這將致使該raw pointer被屢次銷燬當boost::shared_ptr析構時。即不能以下使用:指針

  int *a = new int(5);
  boost::shared_ptr ptr1(a);
  boost::shared_ptr ptr2(a);  //錯誤! 
 
 
boost::intrusive_ptr徹底具有boost::shared_ptr的功能,且不存在shared_ptr的問題,便可以利用raw pointer建立多個intrusive _ptr,其緣由就在於引用計數的ref_count對象,shared_ptr是放在shared_ptr結構裏,而目標對象T經過繼承intrusive_ptr_base將引用計數做爲T對象的內部成員變量,就不會出現同一個對象有兩個引用計數器的狀況出現。
 

 

那麼爲何一般鼓勵你們使用shared_ptr,而不是intrusive_ptr呢, 在於shared_ptr不是侵入性的,能夠指向任意類型的對象; 而intrusive_ptr所要指向的對象,須要繼承intrusive_ptr_base,即便不須要,引用計數成員也會被建立。code

結論:若是建立新類且須要進行傳遞,則繼承intrusive_ptr_base,使用intrusive_ptr。
相關文章
相關標籤/搜索