实现代码
#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
类给做了一些改编,使用这串代码可以直观的感受到引用计数的工作过程,他们可以共享底层的数据,且实现了类似智能指针的效果,代码的输出也完全符合预期
这里重点关注的就是三个地方
拷贝构造函数
、拷贝赋值运算符
、析构函数
,要确保拷贝行为的引用计数增减正确,析构时正确的释放内存
赋值语句
通过在成员函数中打印内容弄清楚了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 到这里整条赋值语句就已完成,接着就要把那个临时的类的对象销毁
strBlob::~strBlob() {
if (--*use == 0) {
delete data;
delete use;
}
}
if (--*use == 0)
这条判断的use
的值为二,减减后变为一,一切都如预料的那样
所以,整条赋值语句完成后就正常的给c
赋了新值,且它的引用计数为一,对于它脱离了a
的数据,a
的引用计数也正常的减了一