weak_ptr智能指針

  weak_ptr是爲配合shared_ptr而引入的一種智能指針,它更像是shared_ptr的一個助手,而不是智能指針,由於它不具備普通指針的行爲,沒有重載operator*和operator->,它的最大做用在於協助shared_ptr,像旁觀者那樣觀測資源的使用狀況。ios

  但它有一個很大的缺點,那就是不能管理循環引用的對象。  函數

#include <boost/shared_ptr.hpp>
#include <iostream>
using namespace std;

class Parent;
class Child;
typedef boost::shared_ptr<Parent> parent_ptr;
typedef boost::shared_ptr<Child> child_ptr;

class Child
{
public:
    Child()
    {
        cout << "Child ..." << endl;
    }
    ~Child()
    {
        cout << "~Child ..." << endl;
    }
    parent_ptr parent_;
};

class Parent
{
public:
    Parent()
    {
        cout << "Parent ..." << endl;
    }
    ~Parent()
    {
        cout << "~Parent ..." << endl;
    }
    child_ptr child_;
};

int main(void)
{
    parent_ptr parent(new Parent);
    child_ptr child(new Child);
    parent->child_ = child;
    child->parent_ = parent;

    return 0;
}
 
        
 
   如上述程序的例子,運行程序能夠發現Child 和 Parent 構造函數各被調用一次,但析構函數都沒有被調用。因爲Parent和Child對象互相引用,它們的引用計數最後都是1,不能自動釋放,而且此時這兩個對象再沒法訪問到。這就引發了內存泄漏。
 
  其中一種解決循環引用問題的辦法是 手動打破循環引用,如在return 0; 以前加上一句 parent->child_.reset(); 此時
        
  當棧上智能指針對象child 析構,Child 對象引用計數爲0,析構Chlid 對象,它的成員parent_ 被析構,則Parent 對象引用計數減爲1,故當棧上智能指針對象parent 析構時,Parent 對象引用計數爲0,被析構。
 
但手動釋放不只麻煩並且容易出錯,這裏主要介紹一下弱引用智能指針 weak_ptr<T> 的用法,下面是簡單的定義:
  
amespace boost
{

    template<typename T> class weak_ptr
    {
    public:
        template <typename Y>
        weak_ptr(const shared_ptr<Y> &r);

        weak_ptr(const weak_ptr &r);

        template<class Y>
        weak_ptr &operator=( weak_ptr<Y> && r );

        template<class Y>
        weak_ptr &operator=(shared_ptr<Y> const &r);


        ~weak_ptr();

        bool expired() const;
        shared_ptr<T> lock() const;
    };
}

兩個經常使用的功能函數:expired()用於檢測所管理的對象是否已經釋放;lock()用於獲取所管理的對象的強引用智能指針。spa

強引用與弱引用設計

強引用,只要有一個引用存在,對象就不能釋放指針

弱引用,並不增長對象的引用計數(其實是不增長use_count_, 會增長weak_count_);但它能知道對象是否存在code

經過weak_ptr訪問對象的成員的時候,要提高爲shared_ptr對象

若是存在,提高爲shared_ptr(強引用)成功
若是不存在,提高失敗

 

對於上述的例子,只須要將Parent 類裏面的成員定義改成以下,便可解決循環引用問題:blog

class Parent
{
public:
    boost::weak_ptr<parent> child_;
};

      

  由於此例子涉及到循環引用,並且是類成員引用着另外一個類,涉及到兩種智能指針,跟蹤起來難度很大,我也沒什麼心情像分析shared_ptr 同樣畫多個圖來解釋流程,這個例子須要解釋的代碼遠遠比shared_ptr 多,這裏只是解釋怎樣使用內存

   下面再舉個例子說明lock()  和 expired() 函數的用法:資源

    

#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/scoped_array.hpp>
#include <boost/scoped_ptr.hpp>
#include <iostream>
using namespace std;

class X
{
public:
    X()
    {
        cout << "X ..." << endl;
    }
    ~X()
    {
        cout << "~X ..." << endl;
    }

    void Fun()
    {
        cout << "Fun ..." << endl;
    }
};
int main(void)
{
    boost::weak_ptr<X> p;
    boost::shared_ptr<X> p3;
    {
        boost::shared_ptr<X> p2(new X);
        cout << p2.use_count() << endl;
        p = p2;
        cout << p2.use_count() << endl;

        /*boost::shared_ptr<X> */
        p3 = p.lock();
        cout << p3.use_count() << endl;
        if (!p3)
            cout << "object is destroyed" << endl;
        else
            p3->Fun();
    }
    /*boost::shared_ptr<X> p4 = p.lock();
    if (!p4)
        cout<<"object is destroyed"<<endl;
    else
        p4->Fun();*/

    if (p.expired())
        cout << "object is destroyed" << endl;
    else
        cout << "object is alived" << endl;

    return 0;
}

  

  從輸出能夠看出,當p = p2; 時並未增長use_count_,因此p2.use_count() 仍是返回1,而從p 提高爲 p3,增長了use_count_, p3.use_count() 返回2;出了大括號,p2 被析構,use_count_ 減爲1,程序末尾結束,p3 被析構,use_count_ 減爲0,X 就被析構了。

 

總結:

  weak_ptr是一個「弱」指針,但它可以完成一些特殊的工做,足以證實它的存在價值。

  weak_ptr被設計爲與shared_ptr共同工做,能夠從一個shared_ptr或者另外一個weak_ptr對象構造,得到資源的觀測權。但weak_ptr沒有共享資源,它的構造不會引發指針引用計數的增長。一樣,在weak_ptr析構時也不會致使引用計數的減小,它只是一個靜靜地觀察者。

  使用weak_ptr的成員函數use_count()能夠觀測資源的引用計數,另外一個成員函數expired()的功能等價於use_count() == 0,但更快,表示觀測的資源(也就是shared_ptr管理的資源)已經不復存在了。

  weak_ptr 沒有重載operator*和->,這是特地的,由於它不共享指針,不能操做資源,這是它弱的緣由。但它可使用一個很是重要的成員函數lock()從被觀測的shared_ptr得到一個可用的shared_ptr對象,從而操做資源。當expired() == true的時候,lock()函數將返回一個存儲空指針的shared_ptr。

相關文章
相關標籤/搜索