C++智能指針讀書筆記
最近在補(bǔ)看《C++ Primer Plus》第六版,這的確是本好書,其中關(guān)于智能指針的章節(jié)解析的非常清晰,一解我以前的多處困惑。C++面試過程中,很多面試官都喜歡問智能指針相關(guān)的問題,比如你知道哪些智能指針?shared_ptr的設(shè)計(jì)原理是什么?如果讓你自己設(shè)計(jì)一個(gè)智能指針,你如何完成?等等……。而且在看開源的C++項(xiàng)目時(shí),也能隨處看到智能指針的影子。這說明智能指針不僅是面試官愛問的題材,更是非常有實(shí)用價(jià)值。
C++通過一對(duì)運(yùn)算符 new 和 delete 進(jìn)行動(dòng)態(tài)內(nèi)存管理,new在動(dòng)態(tài)內(nèi)存中為對(duì)象分配空間并返回一個(gè)指向該對(duì)象的指針,delete接受一個(gè)動(dòng)態(tài)對(duì)象的指針,銷毀對(duì)象并釋放與之相關(guān)的內(nèi)存。然而這樣的動(dòng)態(tài)內(nèi)存的使用很危險(xiǎn),因?yàn)闊o法確保始終能在合適的時(shí)間釋放內(nèi)存對(duì)象。如果忘記釋放內(nèi)存,可能造成內(nèi)存泄露;如果在尚有指針引用內(nèi)存的情況下釋放內(nèi)存,會(huì)產(chǎn)生非法訪問內(nèi)存的指針。
C++11中,新的標(biāo)準(zhǔn)庫(kù)提供了兩種智能指針(smart pointer)類型來更安全地管理對(duì)象。智能指針的使用和常規(guī)指針類似,只是它們多了自動(dòng)釋放所指向的對(duì)象的功能。兩種指針的區(qū)別在于管理底層指針的方式:shared_ptr允許多個(gè)指針指向同一個(gè)對(duì)象,unique_ptr不支持。標(biāo)準(zhǔn)庫(kù)還提供了weak_ptr這一弱指針,指向shared_ptr所管理的對(duì)象。三種類型都定義在頭文件memory中。
shared_ptr的使用和vector很相似,在尖括號(hào)內(nèi)說明所指向?qū)ο蟮念愋停?/p>
shared_ptr<list<int>> p2 // p2是shared_ptr,指向list的int
解引用一個(gè)智能指針就能獲得它所指向的對(duì)象,在if語句中使用智能指針可以判斷它指向的對(duì)象是否為空:
if (p1 && p1->empty())
*p1 = "creat"; // 如果p1非空且指向一個(gè)空的string對(duì)象,解引用p1,為其賦新值creat
最安全的分配和使用shared_ptr的方法是調(diào)用名為make_shared這一標(biāo)準(zhǔn)庫(kù)函數(shù)。此函數(shù)在動(dòng)態(tài)內(nèi)存中分配并初始化它,返回指向此對(duì)象的shared_ptr。該函數(shù)定義在memory中。
make_shared的定義和shared_ptr相似,必須制定要?jiǎng)?chuàng)建對(duì)象的類型,如:
// 指向一個(gè)值為1的int的shared_ptr shared_ptr<int> p3 = make_shared<int>)(1); // 指向一個(gè)值為“www”的string的shared_ptr shared_ptr<string> p4 = make_shared<string>(3, "w"); // 指向一個(gè)初始化的int,值為0 shared_ptr<int> p5 = make_shared<int>)();
也可以使用auto定義對(duì)象保存make_shared,可以省去書寫shared_ptr的麻煩。
shared——ptr中有一個(gè)關(guān)聯(lián)的指示器,稱為引用計(jì)數(shù)??梢钥醋鲆粋€(gè)計(jì)數(shù)器,每當(dāng)shared_ptr對(duì)象進(jìn)行拷貝操作,如用一個(gè)shared_ptr對(duì)象初始化另一個(gè)shared_ptr對(duì)象、作為函數(shù)的實(shí)參、作為函數(shù)返回值時(shí),引用計(jì)數(shù)都會(huì)遞增(視為數(shù)值+1)。當(dāng)賦予shared_ptr新值或者shared_ptr被銷毀時(shí),引用計(jì)數(shù)遞減。當(dāng)引用計(jì)數(shù)減為0,通過析構(gòu)函數(shù),shared_ptr自動(dòng)銷毀所管理的對(duì)象,釋放內(nèi)存。
需要注意的是,如果多個(gè)對(duì)象共享底層數(shù)據(jù),當(dāng)某一對(duì)象被銷毀,不能單方面銷毀底層數(shù)據(jù),例如:
Blob<string> b1; { // 新作用域 Blob<string> b2 = { "x", "b", "b" }; b1 = b2; } // 當(dāng)離開局部作用域,b2被銷毀,然而b2中的元素xbb并不會(huì)被銷毀 // b1指向最初由b2創(chuàng)建的元素,即“x”, "b", "b",b1依舊可以它們
weak_ptr是指向shared_ptr管理的對(duì)象的一種智能指針,然而它不控制所指向?qū)ο蟮纳嫫凇⒁粋€(gè)weak_ptr綁定在shared_ptr上,不會(huì)改變shared_ptr的引用計(jì)數(shù),一旦最后一個(gè)shared_ptr的指向?qū)ο蟊淮蒌N毀,對(duì)象就會(huì)被釋放,有無weak_ptr并無卵影響。我的理解是,weak_ptr提供了指向shared_ptr底層數(shù)據(jù)的功能,控制了shared_ptr對(duì)底層數(shù)據(jù)的訪問。
因?yàn)閣eak_ptr指向的對(duì)象可能不存在(shared_ptr指向的最后一個(gè)對(duì)象被銷毀時(shí)),因而用它不能直接訪問對(duì)象,必須調(diào)用lock函數(shù)檢查其指向的對(duì)象是否存在。很容易寫出一個(gè)選擇語句進(jìn)行控制:
auto bb = make_shared<string>(2, 'b'); weak_ptr<string> xbb(bb); if (shared_pr<int> np = xbb.lock()) { // np不為空條件成立 // 在if語句內(nèi),np和xbb共享對(duì)象 }
補(bǔ)充weak_ptr相關(guān)的函數(shù),便于理解:
w.reset 將w置為空
w.use_count() 與w共享對(duì)象的個(gè)數(shù)
w.expired() 若w.use_count()為0,返回true,否則返回false
w.lock() 若w.expired()為true,返回一個(gè)空shared_ptr,否則返回一個(gè)指向w的對(duì)象的shared_ptr
加入《C++ Primer 5th》中的12.19題參照,題中和“智能指針和異常”并未在本篇隨筆中介紹
#include <iostream> #include <string> #include <vector> #include <memory> #include <initializer_list> using namespace std; using std::string; using std::vector; class StrBlobPtr; class StrBlob { public: friend class StrBlobPtr; // 友元 StrBlobPtr begin(); // 聲明StrBlob類中的begin()和end() StrBlobPtr end(); // 返回一個(gè)指向它自身的StrBlobPtr public: typedef vector<string>::size_type size_type; // 類型別名,size_type = vector<string>::size_type StrBlob::StrBlob(initializer_list<string> il) : data(make_shared<vector<string>>(il)) {}; // 接受一個(gè)initializer_list參數(shù)的構(gòu)造函數(shù)將其參數(shù)傳 遞給對(duì)應(yīng)的vector構(gòu)造函數(shù),通過拷貝列表 StrBlob::StrBlob() : data(make_shared<vector<string>>()) {}; // 構(gòu)造函數(shù),初始化data成員,指向動(dòng)態(tài)分配的vector 中的值初始化vector元素 void push_back(const string &t) { data->push_back(t); } string& StrBlob::front() { check(0, "front on empty StrBlob"); return data->front(); } string& StrBlob::back() { check(0, "back on empty StrBlob"); return data->back(); } void StrBlob::pop_back() { // 刪除尾元素 check(0, "pop_back empty StrBlob"); return data->pop_back(); } string& front() const { return data->front(); }; string& back() const { return data->back(); }; private: shared_ptr<vector<string>> data; void StrBlob::check(size_type i, const string &msg) const { // 檢查元素是否存在 if (i >= data->size()) // 若不存在 throw out_of_range(msg); // 拋出異常 } }; class StrBlobPtr { public: StrBlobPtr() : curr(0) {}; StrBlobPtr(StrBlob &a, size_t sz = 0) : wptr(a.data), curr(sz) {}; string & deref() const { auto p = check(curr, "dereference past end"); return (*p)[curr]; // check成功,返回一個(gè)p指針,指向make_shared指向的vector } // 解引用,make_shared獲取vector,用下表運(yùn)算符返回curr位置上的對(duì)象 StrBlobPtr& incr() { check(curr, "increment past end of StrBlobPtr"); ++curr; return *this; } bool operator!=(const StrBlobPtr& p) { return p.curr != curr; } private: weak_ptr<vector<string>> wptr; size_t curr; shared_ptr<vector<string>> check(size_t i, const string& msg) const { auto rent = wptr.lock(); if (!rent) throw runtime_error("unbound StrBlobPtr"); if (i >= rent->size()) throw out_of_range(msg); return rent; } }; StrBlobPtr StrBlob::begin() { return StrBlobPtr(*this); } StrBlobPtr StrBlob::end() { return StrBlobPtr(*this, data->size()); }
上一篇:詳解C語言中的符號(hào)常量、變量與算術(shù)表達(dá)式
欄 目:C語言
下一篇:C語言中static的作用及C語言中使用靜態(tài)函數(shù)有何好處
本文標(biāo)題:C++智能指針讀書筆記
本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/2641.html
您可能感興趣的文章
- 04-02c語言沒有round函數(shù) round c語言
- 01-10深入理解C++中常見的關(guān)鍵字含義
- 01-10使用C++實(shí)現(xiàn)全排列算法的方法詳解
- 01-10c++中inline的用法分析
- 01-10用C++實(shí)現(xiàn)DBSCAN聚類算法
- 01-10全排列算法的非遞歸實(shí)現(xiàn)與遞歸實(shí)現(xiàn)的方法(C++)
- 01-10C++大數(shù)模板(推薦)
- 01-10淺談C/C++中的static與extern關(guān)鍵字的使用詳解
- 01-10深入C/C++浮點(diǎn)數(shù)在內(nèi)存中的存儲(chǔ)方式詳解
- 01-10深入理解數(shù)組指針與指針數(shù)組的區(qū)別


閱讀排行
- 1C語言 while語句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹的示例代碼(圣誕
- 3利用C語言實(shí)現(xiàn)“百馬百擔(dān)”問題方法
- 4C語言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 04-02c語言函數(shù)調(diào)用后清空內(nèi)存 c語言調(diào)用
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言的正則匹配函數(shù) c語言正則表達(dá)
- 04-02c語言用函數(shù)寫分段 用c語言表示分段
- 04-02c語言中對(duì)數(shù)函數(shù)的表達(dá)式 c語言中對(duì)
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段
- 04-02C語言中怎么打出三角函數(shù) c語言中怎
- 04-02c語言調(diào)用函數(shù)求fibo C語言調(diào)用函數(shù)求
隨機(jī)閱讀
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 01-10delphi制作wav文件的方法
- 01-10C#中split用法實(shí)例總結(jié)
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 04-02jquery與jsp,用jquery
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 01-10使用C語言求解撲克牌的順子及n個(gè)骰子
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載