weak_ptr指针编程实验
weak_ptr指針編程實驗
- 基本知識
- weak_ptr
- 改進后的StrBlob類
- 示例代碼
- my_StrBlob.h
- main.cpp
- 運行結果
本文是本人大一期間在校學習C++課程時所撰寫的實驗報告的摘錄,由于剛上大學,剛接觸計算機編程方面的相關知識,故可能會有很多不足甚至錯誤的地方,還請各位看官指出及糾正。
本文所涉及到的“教材”指:
電子工業出版社《C++ Primary中文版(第5版)》
如需轉載或引用請標明出處。
基本知識
weak_ptr
weak_ptr是一種不控制所指向對象生存期的智能指針,它指向由一個shared_ptr管理的對象。將一個weak_ptr綁定到一個shared_ptr不會改變shared_ptr的引用計數。一旦最后一個指向對象的shared_ptr被銷毀,對象就會被釋放。即使有weak_ptr指向對象,對象也還是會被釋放,因此,weak_ptr的名字體現了“弱”共享對象的特點。
下面是關于weak_ptr的一些操作:
weak_ptr<T> w //空weak_ptr可以指向類型為T的對象 weak_ptr<T> w(sp) //與shared_ptr sp指向相同對象的weak_ptr。T必須能轉換為sp指向的類型 w.reset() //將w值為空 w.lock() //如果與w共享對象的shared_ptr數量為0,則返回一個空shared_ptr;否則返回一個指向w的對象的shared_ptr更多相關操作詳見教材P420,表12.5。
當我們創建一個weak_ptr時,要用一個shared_ptr來初始化它:
auto p = make_shared<int>(99); weak_ptr<int> wp(p);由于weak_ptr的“弱”的特性,創建wp并不會增加p的引用計數,因此wp所指向的對象可能會被釋放掉。由于對象可能不存在,我們不能使用weak_ptr直接訪問對象,因而必須調用weak_ptr的成員函數lock,該函數檢查weak_ptr指向的對象是否存在。若存在,lock返回一個指向共享對象的shared_ptr,否則返回一個空的shared_ptr。
改進后的StrBlob類
關于StrBlob類可以看這篇文章。
為了做到不影響給定的StrBlob所指向vector的生存期,同時也可以阻止用戶訪問一個不再存在的vector的目的,將給以前的StrBlob定義一個伴隨指針類StrBlobPtr。該類會保存一個weak_ptr,在初始化時使它指向StrBlob的成員data。
StrBlobPtr有兩個數據成員:weak_ptr類型的wptr,指向空或者一個StrBlob中的vector;vector::size_type類型的curr,用于保存當前對象所表示的元素的下標(實際上是給shared_ptr使用的下標)。此外還將有一個成員函數check用于檢查解引用StrBlobPtr是否安全,另一個成員函數deref用于解引用對象。
在StrBlob中,添加了兩個成員函數begin和end,用于代替普通begin函數和end函數的作用(返回對應的迭代器),新定義的這兩個函數將使用StrBlobPtr以免在for循環中改變StrBlob中data的引用計數。為了做到檢查指向位置是否合法的同時可以方便地解引用,讓StrBlobPtr的成員函數check在檢查通過時返回對應的shared_ptr,因此成員函數deref實際上是間接地通過解引用一個shared_ptr來獲得weak_ptr指向對象,又因為是在函數中,故不會影響指向對象的生存期
示例代碼
my_StrBlob.h
#ifndef MY_STRBLOB_H #define MY_STRBLOB_H #include <vector> #include <string> #include <memory> //包含標準庫類型initializer_list,以使用有可變形參的函數 #include <initializer_list> //包含并使用一些標準庫異常 #include <stdexcept>using namespace std; class StrBlobPtr; //提前聲明,StrBlob中的友類聲明所需//定義StrBlob類 class StrBlob {friend class StrBlobPtr; //友元聲明,聲明StrBlobPtr是StrBlob的友元//public的成員可被整個程序使用 public:typedef vector<string>::size_type size_type; //定義vector<string>的size_type類型為size_typeStrBlob(); //無形參的構造函數聲明StrBlob(initializer_list<string> list); //有可變形參的構造函數聲明size_type size() const { return data->size(); } //定義StrBlob的成員函數sizebool empty() const { return data->empty(); } //定義StrBlob的成員函數empty//添加和刪除元素的操作void push_back(const string& t) { data->push_back(t); } //定義StrBlob的成員函數push_backvoid pop_back(); //StrBlob的成員函數pop_back的聲明 //訪問元素的操作string& front(); //StrBlob的成員函數front的聲明const string& front() const; //const版本的StrBlob的成員函數front的聲明string& back(); //StrBlob的成員函數back的聲明const string& back() const; //const版本的StrBlob的成員函數back的聲明//提供給StrBlobPtr的接口,定義StrBlobPtr后才能定義這兩個函數StrBlobPtr begin(); //StrBlob的成員函數begin的聲明StrBlobPtr end(); //StrBlob的成員函數end的聲明//private的成員只能被類的成員函數訪問 private:shared_ptr<vector<string>> data; //該類只有一個成員:指向存儲string的vector的智能指針void check(size_type i, const string& msg) const; //如果data[i]不合法,拋出一個異常,顯示msg };StrBlob::StrBlob() :data(make_shared<vector<string>>()) { } //定義無形參的構造函數 StrBlob::StrBlob(initializer_list<string> list) : data(make_shared<vector<string>>(list)) { } //定義有可變形參的構造函數void StrBlob::check(size_type i, const string& msg) const //check函數的定義 {if (i >= data->size()) //如果i超出vector的范圍throw out_of_range(msg); //則拋出異常 }string& StrBlob::front() //普通版本的front函數 {check(0, "front on empty StrBlob"); //如果vector為空,則check拋出一個異常return data->front(); //返回data的成員函數front的返回值(起始元素的引用) }const string& StrBlob::front() const //const版本的front函數 {check(0, "front on empty StrBlob"); //如果vector為空,則check拋出一個異常return data->front(); //返回data的成員函數front的返回值(起始元素的引用) }string& StrBlob::back() //普通版本的back函數 {check(0, "back on empty StrBlob"); //如果vector為空,則check拋出一個異常return data->back(); //返回data的成員函數back的返回值(尾元素的引用) }const string& StrBlob::back() const //const版本的back函數 {check(0, "back on empty StrBlob"); //如果vector為空,則check拋出一個異常return data->back(); //返回data的成員函數back的返回值(尾元素的引用) }void StrBlob::pop_back() //定義SrtBlob的成員函數pop_back {check(0, "pop_back on empty StrBlob"); //如果vector為空,則check拋出一個異常data->pop_back(); //返回data的成員函數pop_back的返回值 }class StrBlobPtr {friend bool eq(const StrBlobPtr& lhs, const StrBlobPtr& rhs); //聲明函數eq是StrBlobPtr是的友元函數public:StrBlobPtr() :curr(0) { } //無形參的構造函數定義(弱指針位置指向首元素)StrBlobPtr(StrBlob& a, size_t sz = 0) :wptr(a.data), curr(sz) { } //有形參的構造函數定義(默認位置是首元素) string& deref() const; //StrBlobPtr的成員函數deref的聲明StrBlobPtr& incr(); //StrBlobPtr的成員函數incr的聲明StrBlobPtr& decr(); //StrBlobPtr的成員函數decr的聲明private:weak_ptr<vector<string>> wptr; //成員wptr:一個指向vector<string>的weak_ptrsize_t curr; //成員curr:用于指示vector中的當前位置shared_ptr<vector<string>> check(size_t i, const string& msg) const; //check函數, };//如果wptr指向的對象不存在,或位置超出vector,則拋出相應的異常 shared_ptr<vector<string>> StrBlobPtr::check(size_t i, const string& msg) const {auto ret = wptr.lock(); //ret是一個指向vector<string>的shared_ptrif (!ret) //如果wptr指向的對象不存在throw runtime_error("unbound StrBlobPtr");if (i >= ret->size()) //如果指向的位置超出vectorthrow out_of_range(msg);return ret; //返回相應的shared_ptr }string& StrBlobPtr::deref() const //解引用指向當前位置的shared_ptr {auto p = check(curr, "dereference past end"); //檢查當前位置是否合法return (*p)[curr]; //返回當前位置的解引用 }StrBlobPtr& StrBlobPtr::incr() //遞增weak_ptr指向的位置 {check(curr, "increment past end of StrBlobPtr");//檢查位置curr++; //遞增指向位置return *this; //返回當前的StrBlobPtr }StrBlobPtr& StrBlobPtr::decr() {curr--; //遞減指向位置check(-1, "decrement past begin of StrBlobPtr");//檢查位置return *this; //返回當前的StrBlobPtr }StrBlobPtr StrBlob::begin() {return StrBlobPtr(*this); //返回一個弱指針指向StrBlob成員data首元素的StrBlobPtr }//返回一個弱指針指向StrBlob成員data尾元素的StrBlobPtr StrBlobPtr StrBlob::end() {auto ret = StrBlobPtr(*this, data->size()); //更改構造函數默認參數為data的大小,使弱指針指向尾元素return ret; }bool eq(const StrBlobPtr& lhs, const StrBlobPtr& rhs) {auto l = lhs.wptr.lock(), r = rhs.wptr.lock();if (l == r) //如果兩個shared_ptr指向同一位置return (!r || lhs.curr == rhs.curr); //則返回ture(r與l可能指向空)elsereturn false; }bool neq(const StrBlobPtr& lhs, const StrBlobPtr& rhs) {return !eq(lhs, rhs); //上個函數的相反 }#endifmain.cpp
#include <iostream> #include "my_StrBlob.h" //包含自定義的頭文件用雙引號int main(void) {StrBlob b1; //用無形參的構造函數初始化StrBlob類型b1{StrBlob b2({ "China", "America", "Japan" }); //用有可變形參的構造函數初始化StrBlob類型b2b1 = b2; //將b2的值賦給b1b2.push_back("France"); //在b2末尾添加元素“France”cout << b2.size() << endl; //輸出b2}//b2的作用域結束,其智能指針的的計數器減一 cout << b1.size() << endl; //使用自定義的成員函數size輸出b1的大小cout << b1.front() << " " << b1.back() << endl; //使用自定義的成員函數front、back輸出b1的首位兩個元素b1.pop_back(); //刪除b1的尾元素const StrBlob b3 = b1; //復制一份const的b1給b3,b1智能指針的計數器加一cout << b3.front() << " " << b3.back() << endl; //使用const版本的自定義的成員函數front、back輸出b3的首位兩個元素for (auto it = b1.begin(); neq(it, b1.end()); it.incr())//使用弱指針遍歷b1,以免影響其計數器的值cout << it.deref() << endl;system("pause");return 0; }運行結果
總結
以上是生活随笔為你收集整理的weak_ptr指针编程实验的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 共享智能指针编程实验
- 下一篇: allocator类编程实验