1. 程式人生 > >shared_ptr和weak_ptr智慧指標結合使用的一個例項

shared_ptr和weak_ptr智慧指標結合使用的一個例項

結合shared_ptrweak_ptr一個例項

         感覺這個例子很好, 結合了很多知識技術。這個例項功能是簡單模擬實現std::vector<std::string> 部分功能。 (只是非常簡單一些操作),當然也可以繼續擴充套件,甚至擴充套件為模板,主要是用於學習。使用兩個類實現,分別是StrBlobStrBlobPtr

StrBlob主要使用shared_ptr類物件來管理資源,StrBlobPtr主要使用weak_ptr類物件來管理資源。底層操作資料物件

std::vector<std::string>

學習點: (真心感覺這個例子很棒)

1、StrBlob

StrBlobPtr的關係,基本上類似容器和迭代器的關係,很好將他們區分開來。

2、對記憶體資源的管理,非常巧妙。

3、對異常考慮

下面是本例的完整程式碼, 然後再簡單分析一下自己理解。

verStr.h

#ifndef VECSTR_H_INCLUDED
#define VECSTR_H_INCLUDED
#include<memory>
#include<vector>
#include<string>


class StrBlobPtr;

class StrBlob
{
public:
    using size_type = std::vector<std::string>::size_type;

    // in order to access the data member in StrBlobPtr class
    friend class StrBlobPtr;
    //constructor
    StrBlob()
        :data(std::make_shared<std::vector<std::string> >()) {}
    StrBlob(const std::initializer_list<std::string> lisStr)
        : data(std::make_shared<std::vector<std::string> >(lisStr)) {}

    //the operator of size
    size_type size() const{ return data->size();}
    bool empty() const { return data->empty();}

    //add and remove elements
    void push_back(const std::string& str) {data->push_back(str);}
    void pop_back()
    {
        check(0,"pop_back on empty StrBlob");
        data->pop_back();
    }

    //element access
    std::string& front() const
    {
       check(0,"front on empty StrBlob");
       return data->front();
    }
    std::string& back() const
    {
        check(0,"back on empty StrBlob");
        return data->back();
    }

    //return StrBlobPtr to the first and one past the last elements
    StrBlobPtr begin();
    StrBlobPtr end();
private:
    std::shared_ptr<std::vector<std::string> > data;

    // throws msg if data[_size] isn't valid
    void check(size_type _size,const std::string& msg) const
    {
        if(_size>=data->size())
            throw std::runtime_error(msg);
    }
};


class StrBlobPtr
{
public:
    StrBlobPtr() :cur(0){}
    StrBlobPtr(StrBlob& str,std::size_t sz = 0)
        :wptr(str.data),cur(sz)
    {

    }
    // operator of elements
    bool operator!=(const StrBlobPtr& p) { return p.cur!= cur; }
    std::string& deref() const;
    StrBlobPtr& incr(); // prefix version

private:
    std::shared_ptr<std::vector<std::string> >
        check(std::size_t ,const std::string& msg) const;

    //store a weak_ptr, which means the underlying vector might be destroyed
    std::weak_ptr<std::vector<std::string> > wptr;
    std::size_t cur;  // current position within the array
};

std::shared_ptr<std::vector<std::string> >
    StrBlobPtr::check(std::size_t _size,const std::string& msg) const
    {
        auto ret = wptr.lock(); //return the shared_ptr pointer to the object to which wptr points from lock to initialize ret
        if(!ret)
            throw std::runtime_error("unbound StrBlobPtr");
        if(_size>=ret->size())
            throw std::out_of_range(msg);
        return ret;
    }
std::string& StrBlobPtr::deref() const
{
    auto p = check(cur,"dereference past end");
    return (*p)[cur];
}

StrBlobPtr& StrBlobPtr::incr()
{
    check(cur,"increment past end of StrBlobPtr");
    ++cur;
    return *this;
}

StrBlobPtr StrBlob::begin()
{
    return StrBlobPtr(*this);
}
StrBlobPtr StrBlob::end()
{
    auto ret = StrBlobPtr(*this,data->size());
    return ret;
}


#endif // VECSTR_H_INCLUDED

以下是一個測試用例,從一個檔案中讀取字串,將其儲存再StrBlob中,再將其打印出來。

#include <iostream>
#include<fstream>
#include<sstream>
#include<algorithm>
#include"vecStr.h"
const std::string fileName = "input.txt";
int main()
{
    StrBlob str;
    std::ifstream fs(fileName);
    std::string buffer;
    while(getline(fs,buffer))
        str.push_back(buffer);

    for(StrBlobPtr it = str.begin();it!=str.end(); it.incr())
    {
        std::cout<<it.deref()<<std::endl;
    }
    return 0;
}

簡單分析:(以下資源是指std::vector<std::string>

shared_ptr、weak_ptr具體型別如下

std::shared_ptr<std::vector<std::string> > data;
std::weak_ptr<std::vector<std::string> > wptr;

我們知道,我們用StrBlob去顯示初始化StrBlobPtr物件, 主要是使用data去初始化wptr

 StrBlobPtr(StrBlob& str,std::size_t sz = 0)
        :wptr(str.data),cur(sz)
    {

    }

當構造完StrBlobPtr物件,shared_ptr所管理的資源使用者是不會增加的(即資源引用計數不會自增一),weak_ptr只是指向一塊被shared_ptr管理的資源,所擁有的這份資源的管理權在shared_ptr, 這也導致我們在使用weak_ptr所指向的資源的時候,需要檢查一下它所指向的資源是否存在(因為shared_ptr所管理資源可能被刪除)。  在StrBlobPtrcheck中函式實現。當weak_ptr所指向的資源不存在時,便丟擲一個異常runtime_error

std::shared_ptr<std::vector<std::string> >
    StrBlobPtr::check(std::size_t _size,const std::string& msg) const
    {
        auto ret = wptr.lock(); //return the shared_ptr pointer to the object to which wptr points from lock to initialize ret
        if(!ret)
            throw std::runtime_error("unbound StrBlobPtr");
        if(_size>=ret->size())
            throw std::out_of_range(msg);
        return ret;
    }

這裡還有一個地方需要注意,weak_ptr是沒有辦法直接操作它所指向的資源的(一個原因是它所指向的資源有可能被刪除),需要藉助shared_ptr物件,通過呼叫wptr.lock(),當wptr指向非空時,返回一個shared_ptr物件,指向的wptr所指向的資源, 並用這個物件去初始化ret(建立了一個shared_pre物件名ret,這時候weak_ptr所返回的資源管理使用者會增加多一個,即ret這個使用者,資源引用計數增加一個)。如果wptr指向空,那麼這時候lock會返回一個nullptr空指標,程式會丟擲一個異常。

現在問題又來了,ret這個使用者作為check函式的返回值,意味著ret這個使用者並沒有在check函式結束後釋放對它所指向的資源的管理權(資源引用不會減少)那讓我們來跟蹤一個ret這個使用者去哪裡了。 StrBlobPtr類有derefincr成員呼叫這個函式,如下。

std::string& StrBlobPtr::deref() const
{
    auto p = check(cur,"dereference past end");
    return (*p)[cur];
}

StrBlobPtr& StrBlobPtr::incr()
{
    check(cur,"increment past end of StrBlobPtr");
    ++cur;
    return *this;
}

顯然當這兩個函式分別執行完後,ret將作為函式中區域性物件銷燬了,這時候(資源引用計數遞減1)。 非常巧妙,非常簡單,這樣便保證了資源不會洩漏。

在仔細看看,StrBlobPtr物件是如何解引用獲取StrBlob物件的值,這裡並不是在StrBlobPtr類中過載operator *實現解引用。而是使用了refef成員函式代替(為了方便),

容易看到是通過shared_ptr物件操作下標cur,取得了該資源(vector<string>)所對應的值( 相當於(*data)[cur]).

再來看看如何對StrBlobPtr物件實現遞增,這裡同樣也不是過載operator ++()或者是operator ++(int)  分別對應前置遞增跟後置遞增, 這裡使用incr()函式,結合資料成員

 std::weak_ptr<std::vector<std::string> > wptr;
 std::size_t cur;  // current position within the array

模擬實現前置遞增,很容易看出來。

想想上述物件是否能夠滿足建立const StrBlob const StrBlobPtr 物件??

顯然是不符合我們使用習慣,需要再過載如下函式:

StrBlob中(以下只提供宣告宣告,實現類似)

 StrBlobPtr begin() const ;
 StrBlobPtr end();  const;
StrBlobPtr中 
 const std::string& deref() const;

以上分析是個人理解,有不妥歡迎指出來。

參考:

相關推薦

shared_ptrweak_ptr智慧指標結合使用的一個例項

結合shared_ptr、weak_ptr一個例項          感覺這個例子很好, 結合了很多知識技術。這個例項功能是簡單模擬實現std::vector<std::string> 部分功能。 (只是非常簡單一些操作),當然也可以繼續擴充套件,甚至擴充套件

C++ 智慧指標一個實現(基於模板Shared_ptr

自己實現了一個C++的智慧指標。 基於Shared_ptr來實現,支援預設構造,拷貝構造,移動構造, 引用計數器, 注意智慧指標中存放的指標地址一旦被一個智慧指標物件託管以後,不要再直接拿此地址來初始化其他物件,否則會引發多次洩漏的問題。(所以還是要特別小心) 如果要初始化

淺析shared_ptr weak_ptr、定製刪除器

   通過boost::weak_ptr來打破迴圈引用 ,由於弱引用不更改引用計數,類似普通指標,只要把迴圈引用的一方使用弱引用,即可解除迴圈引用 定製刪除器;定製刪除器 為什麼在shared_ptr中介紹刪除器呢?(因為auto_ptr存在缺陷,scoped_ptr功能不全) #define _CRT_SE

c++智慧指標(三)之shared_ptrnew結合使用

shared_ptr和new結合使用 我們除了使用make_shared來初始化一個智慧指標,還可以使用new返回的指標來初始化智慧指標。 shared_ptr<int> p1(new int(42));//p1指向一個值為42的int sh

【轉載】C++ 智慧指標shared_ptr/weak_ptr)原始碼分析

發現一篇對C++11智慧指標分析很透徹的文章,特轉載備忘! 以下轉載自:https://blog.csdn.net/ithiker/article/details/51532484?utm_source=blogxgwz1   C++11目前已經引入了unique_ptr, shared_pt

C++之智慧指標std::shared_ptr簡單使用理解

1  智慧指標std::shared_ptr相關知識和如何使用 我們這裡先說下智慧指標std::shared_ptr,因為我看到我我們專案c++程式碼裡面用得很多,我不是不會,所以記錄學習下 先讓ubuntu終端支援c++11,如果自己的電腦還沒配置號,可以先看下我的這篇部落格

C++智慧指標shared_ptr,uniqe_ptr,weak_ptr

動態記憶體 在C++中,動態記憶體的管理是通過一對運算子來完成的:new和delete。 new:在動態記憶體中為物件分配空間,並返回一個指向該物件的指標 delete:接受一個動態物件的指標,銷燬該物件,並釋放與之關聯的記憶體 動態記憶體的使用需要十分小心,因為要在程式設計的時候要

c++ 之四大智慧指標 std::auto_ptr std::shared_ptr std::unuque std::weak_ptr 比較總結

1. 動態記憶體必要性 程式不知道自己需要多少物件;  程式不知道物件的準確型別;  程式需要在多個物件之間共享資料; 2. 動態記憶體在哪裡 程式有靜態記憶體、棧記憶體。靜態記憶體用來儲存區域性static物件、類static資料成員以及定義在任何函式之外的變數

智慧指標--scoped_ptr shared_ptr weak_ptr

所謂智慧指標就是智慧/自動化的管理指標所指向的動態資源的釋放; scopde_ptr--防拷貝 什麼叫做防拷貝?就是不允許一個地址空間的指標賦值給另一個指標,導致有兩個指標指向同一個地址;也就是說防拷貝能保證地址與指標是一一對應的關係; 實現方法:要拷貝,就需要通過物件來呼

C++ 智慧指標shared_ptr/weak_ptr)原始碼分析

C++11目前已經引入了unique_ptr, shared_ptr, weak_ptr等智慧指標以及相關的模板類enable_shared_from_this等。shared_ptr實現了C++中的RAII機制,它不僅僅具有一般指標(build-in/raw)的特性,更重要的是它可以自動管理使用者

C++11--智慧指標shared_ptrweak_ptr,unique_ptr

共享指標 shared_ptr /*********** Shared_ptr ***********/ // 為什麼要使用智慧指標,直接使用裸指標經常會出現以下情況 // 1. 當指標的生命長於所指的資源:野指標 // 2. 當指標的生命短於所指的資源:資源洩漏 // // 智慧指標: 確保指標和資源的生

詳細分析智慧指標shared_ptr存在的迴圈引用缺陷,以及通過weak_ptr來解決

模擬實現的簡單的shared_ptr: template <class T> class SharedPtr{ public: SharedPtr(T* ptr) :_ptr(ptr), _refCount(new in

智慧指標 auto_ptr、scoped_ptr、shared_ptrweak_ptr

  什麼是RAII? RAII是Resource Acquisition Is Initialization的簡稱,是C++語言的一種管理資源、避免洩漏的慣用法。 RAII又叫做資源分配即初始化,即:定義一個類來封裝資源的分配和釋放,在建構函式完成資源的分配和初始化,在解構函式完成資源的清理,可以保證資源

C++智慧指標shared_ptr使用例項

被new/delete折磨過之後,才能真正體會智慧指標有多好用。 智慧指標是用於管理指標的類。 其中shared_ptr是專門管理那些可能被多個地方用到的指標的類。 C++11中智慧指標的標頭檔案是: #include <memory>

C++11 智慧指標std::shared_ptr/std::unique_ptr/std::weak_ptr

std::shared_ptr std::shared_ptr 是一種智慧指標,它能夠記錄多少個 shared_ptr 共同指向一個物件,從而消除顯示的呼叫 delete,當引用計數變為零的時候就

boost庫的智慧指標shared_ptr結合容器vector的使用

將n個shared_ptr放在vector中,vector會保持每個shared_ptr的引用;vector銷燬時,shared_ptr會自動銷燬所持物件,釋放記憶體 #include <ios

Boost智慧指標——scoped_ptrshared_ptr

boost::scoped_ptr和std::auto_ptr非常類似,是一個簡單的智慧指標,它能夠保證在離開作用域後物件被自動釋放。下列程式碼演示了該指標的基本應用: #include <string>#include <iostream>#include <boost/

智慧指標異常、 weak_ptr、unique_ptr

12.1.4智慧指標和異常 1.在塊中建立的動態記憶體,如果是由內建指標來指向這塊記憶體,那麼若是在塊結束時未delete這個指標,則該記憶體不會被釋放,若在delete之前發生異常,由於還沒執行delete操作,記憶體也不會被釋放;但若是由智慧指標來指向這塊記憶體,那無論

stl中auto_ptr,unique_ptr,shared_ptr,weak_ptr四種智慧指標使用總結

在一次面試過程中被問到了stl中的四種智慧指標的用法 由於經驗不足,我只知道auto_ptr和shared_ptr,然後還說了一個弱...    然後面試官就提示是weak_ptr,之後他又主動說出了unique_ptr 我也只對auto_ptr和shared_ptr做了一

幾種智慧指標的比較(std::auto_ptr、boost::scoped_ptr、boost::shared_ptr、boost::weak_ptr

一、std::auto_ptr auto_ptr的建構函式接受原始指標作為引數,雖然它是一個物件,但是過載了operator*和operator->,可以把它用在大多數普通指標可用的地方。當退出作用域時,auto_ptr物件的解構函式會釋放原始指標。 例: int m