1. 程式人生 > >boost shared ptr的使用方法

boost shared ptr的使用方法

               

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: 1a1 reference count: 2a2 reference count: 2a2 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 throwsshared_ptr(std::nullptr_t); // never throwstemplate<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.}
 

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即可使用。