C++智能指針念書筆記。本站提示廣大學習愛好者:(C++智能指針念書筆記)文章只能為提供參考,不一定能成為您想要的結果。以下是C++智能指針念書筆記正文
比來在補看《C++ Primer Plus》第六版,這切實其實是本好書,個中關於智能指針的章節解析的異常清楚,一解我之前的多處迷惑。C++面試進程中,許多面試官都愛好問智能指針相干的成績,好比你曉得哪些智能指針?shared_ptr的設計道理是甚麼?假如讓你本身設計一個智能指針,你若何完成?等等……。並且在看開源的C++項目時,也能到處看到智能指針的影子。這解釋智能指針不只是面試官愛問的題材,更長短常有適用價值。
C++經由過程一對運算符 new 和 delete 停止靜態內存治理,new在靜態內存中為對象分派空間並前往一個指向該對象的指針,delete接收一個靜態對象的指針,燒毀對象並釋放與之相干的內存。但是如許的靜態內存的應用很風險,由於沒法確保一直能在適合的時光釋放內存對象。假如忘卻釋放內存,能夠形成內存洩漏;假如在另有指針援用內存的情形下釋放內存,會發生不法拜訪內存的指針。
C++11中,新的尺度庫供給了兩種智能指針(smart pointer)類型來更平安地治理對象。智能指針的應用和慣例指針相似,只是它們多了主動釋放所指向的對象的功效。兩種指針的差別在於治理底層指針的方法:shared_ptr許可多個指針指向統一個對象,unique_ptr不支撐。尺度庫還供給了weak_ptr這一弱指針,指向shared_ptr所治理的對象。三品種型都界說在頭文件memory中。
shared_ptr的應用和vector很類似,在尖括號內解釋所指向對象的類型:
shared_ptr<string> p1 // p1是shared_ptr,指向string類型
shared_ptr<list<int>> p2 // p2是shared_ptr,指向list的int
解援用一個智能指針就可以取得它所指向的對象,在if語句中應用智能指針可以斷定它指向的對象能否為空:
// 假如p1非空,檢討p1能否指向一個空的string對象
if (p1 && p1->empty())
*p1 = "creat"; // 假如p1非空且指向一個空的string對象,解援用p1,為其賦新值creat
最平安的分派和應用shared_ptr的辦法是挪用名為make_shared這一尺度庫函數。此函數在靜態內存平分配並初始化它,前往指向此對象的shared_ptr。該函數界說在memory中。
make_shared的界說和shared_ptr類似,必需制訂要創立對象的類型,如:
// 指向一個值為1的int的shared_ptr shared_ptr<int> p3 = make_shared<int>)(1); // 指向一個值為“www”的string的shared_ptr shared_ptr<string> p4 = make_shared<string>(3, "w"); // 指向一個初始化的int,值為0 shared_ptr<int> p5 = make_shared<int>)();
也能夠應用auto界說對象保留make_shared,可以省去書寫shared_ptr的費事。
shared——ptr中有一個聯系關系的指導器,稱為援用計數。可以看作一個計數器,每當shared_ptr對象停止拷貝操作,如用一個shared_ptr對象初始化另外一個shared_ptr對象、作為函數的實參、作為函數前往值時,援用計數都邑遞增(視為數值+1)。當付與shared_ptr新值或許shared_ptr被燒毀時,援用計數遞加。當援用計數減為0,經由過程析構函數,shared_ptr主動燒毀所治理的對象,釋放內存。
須要留意的是,假如多個對象同享底層數據,當某一對象被燒毀,不克不及片面燒毀底層數據,例如:
Blob<string> b1; { // 新感化域 Blob<string> b2 = { "x", "b", "b" }; b1 = b2; } // 當分開部分感化域,b2被燒毀,但是b2中的元素xbb其實不會被燒毀 // b1指向最後由b2創立的元素,即“x”, "b", "b",b1照舊可以它們
weak_ptr是指向shared_ptr治理的對象的一種智能指針,但是它不掌握所指向對象的生計期。將一個weak_ptr綁定在shared_ptr上,不會轉變shared_ptr的援用計數,一旦最初一個shared_ptr的指向對象被摧燒毀,對象就會被釋放,有沒有weak_ptr並沒有卵影響。我的懂得是,weak_ptr供給了指向shared_ptr底層數據的功效,掌握了shared_ptr對底層數據的拜訪。
由於weak_ptr指向的對象能夠不存在(shared_ptr指向的最初一個對象被燒毀時),因此用它不克不及直接拜訪對象,必需挪用lock函數檢討其指向的對象能否存在。很輕易寫出一個選擇語句停止掌握:
auto bb = make_shared<string>(2, 'b'); weak_ptr<string> xbb(bb); if (shared_pr<int> np = xbb.lock()) { // np不為空前提成立 // 在if語句內,np和xbb同享對象 }
彌補weak_ptr相干的函數,便於懂得:
w.reset 將w置為空
w.use_count() 與w同享對象的個數
w.expired() 若w.use_count()為0,前往true,不然前往false
w.lock() 若w.expired()為true,前往一個空shared_ptr,不然前往一個指向w的對象的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(); // 前往一個指向它本身的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)) {}; // 接收一個initializer_list參數的結構函數將其參數傳 遞給對應的vector結構函數,經由過程拷貝列表 StrBlob::StrBlob() : data(make_shared<vector<string>>()) {}; // 結構函數,初始化data成員,指向靜態分派的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勝利,前往一個p指針,指向make_shared指向的vector } // 解援用,make_shared獲得vector,用下表運算符前往curr地位上的對象 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()); }