#include "../head.h" #include <memory> #include <initializer_list> class strBlob { public: typedef vector<string>::size_type size_type; strBlob(); strBlob(initializer_list<string> il); strBlob(const strBlob &sb); strBlob& operator=(const strBlob &rhs); size_type size() const {return data->size();} bool empty() const {return data->empty();} size_t get_use() {return *use;} void push_back(const string &t) {data->push_back(t);} void pop_back(); string& front() const; string& back() const; ~strBlob(); private: vector<string> *data; void check(size_type i, const string &msg) const; size_t *use; }; strBlob::strBlob() : data(new vector<string>()), use(new size_t(1)) { } strBlob::strBlob(initializer_list<string> il) : data(new vector<string>(il)), use(new size_t(1)) { } strBlob::strBlob(const strBlob &sb) : data(sb.data), use(sb.use) {++*use;} strBlob& strBlob::operator=(const strBlob &rhs) { ++*rhs.use; if (--*use == 0) { delete data; delete use; } data = rhs.data; use = rhs.use; return *this; } void strBlob::check(size_type i, const string &msg) const { if (i >= data->size()) throw out_of_range(msg); } void strBlob::pop_back() { check(0, "pop_back on empty strBlob"); data->pop_back(); } string& strBlob::front() const { check(0, "front on empty strBlob"); return data->front(); } string& strBlob::back() const { check(0, "back on empty strBlob"); return data->back(); } strBlob::~strBlob() { if (--*use == 0) { delete data; delete use; } } int main(int argc, char** argv) { strBlob a = {"hello", "world"}; a.pop_back(); strBlob b = a; b.push_back("fromb"); cout << "The last word in a: " << a.back() << endl; cout << "The first word in b: " << b.front() << endl; strBlob c = b; cout << "After c = b; there are " << a.get_use() << " use from a now" << endl; c = {"ni", "hao"}; cout << "After assign value to c, there are " << a.get_use() << " use from a now" << endl; return 0; }
The last word in a: fromb The first word in b: hello After c = b; there are 3 use from a now After assign value to c, there are 2 use from a now
這是從《C++ primer》
13-27
的習題引伸出來的代碼,將前文strBlob
類給作了一些改編,使用這串代碼能夠直觀的感覺到引用計數的工做過程,他們能夠共享底層的數據,且實現了相似智能指針的效果,代碼的輸出也徹底符合預期函數
這裏重點關注的就是三個地方
拷貝構造函數
、拷貝賦值運算符
、析構函數
,要確保拷貝行爲的引用計數增減正確,析構時正確的釋放內存this
經過在成員函數中打印內容弄清楚了c = {"ni", "hao"};
這條賦值語句工做的整個過程
1 賦值號右邊的內容經過使用列表構造函數生成了一個臨時的類的對象,此時它的引用計數爲一
2 臨時的類的對象經過拷貝賦值運算符給c
賦值,此時進入到拷貝賦值運算符中指針
strBlob& strBlob::operator=(const strBlob &rhs) { ++*rhs.use; if (--*use == 0) { delete data; delete use; } data = rhs.data; use = rhs.use; return *this; }
rhs
,它的引用計數加一,此時它的引用計數爲二if (--*use == 0)
這條判斷減減的use
是對象a
中的引用計數use
,行爲相似於書中給shared_ptr賦予一個新值,計數器遞減
c
,包括對應的引用計數,依舊是二3 到這裏整條賦值語句就已完成,接着就要把那個臨時的類的對象銷燬code
strBlob::~strBlob() { if (--*use == 0) { delete data; delete use; } }
if (--*use == 0)
這條判斷的use
的值爲二,減減後變爲一,一切都如預料的那樣因此,整條賦值語句完成後就正常的給c
賦了新值,且它的引用計數爲一,對於它脫離了a
的數據,a
的引用計數也正常的減了一對象