shared_ptr和weak_ptr智慧指標結合使用的一個例項
結合shared_ptr、weak_ptr一個例項
感覺這個例子很好, 結合了很多知識技術。這個例項功能是簡單模擬實現std::vector<std::string> 部分功能。 (只是非常簡單一些操作),當然也可以繼續擴充套件,甚至擴充套件為模板,主要是用於學習。使用兩個類實現,分別是StrBlob、StrBlobPtr。
StrBlob主要使用shared_ptr類物件來管理資源,StrBlobPtr主要使用weak_ptr類物件來管理資源。底層操作資料物件
std::vector<std::string>
學習點: (真心感覺這個例子很棒)
1、StrBlob
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所管理資源可能被刪除)。
在StrBlobPtr中check中函式實現。當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類有deref、incr成員呼叫這個函式,如下。
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_ptr和weak_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_ptr和new結合使用
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_ptr,weak_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_ptr、weak_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_ptr和shared_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