#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
的引用计数也正常的减了一对象