定义行为象值的类,对于这种定义的类,每一个对象都应该有一份自己的拷贝.它们的改变不会影响原对象.
[练习]:希望StrBlob的行为像一个值,定义相应的拷贝控制成员.
StrBlob(const StrBlob & rhs)
{
data = make_shared<vector<string>>( vector<string>(*rhs.data));
}
StrBlob& operator= (const StrBlob& rhs)
{
data = make_shared<vector<string>>(vector<string>(*rhs.data));
return *this;
}
定义对象行为像指针.我们需要拷贝指针成员本身而不是所指的对象.而最好的办法就是使用shared_ptr来管理资源.这在前面的StrBlob类中就已经体现了.但是如果我们想直接管理资源,使用引用计数是一个有效的办法.我们设计自己的引用计数,而不使用智能指针.
基本方式如下:除了初始化对象外,每个构造函数(除了拷贝构造函数)要创建一个引用计数.,并初始化为1.
拷贝构造函数将计数递增.
析构函数递减计数,如果计数是0则释放资源.
拷贝赋值运算符递增右侧对象,递减左侧对象.如果计数是0则释放资源.
计数器必须用动态内存保存,这样才能够共享数据.
[练习]定义一个使用引用计数的Hasptr类
class Hasptr
{
public:
Hasptr(const string & s = string()) :ps(new string(s)),i(0),use(new size_t(1)) {}
Hasptr(const Hasptr & h) : ps(h.ps), i(h.i), use(h.use){ ++*use; }
~Hasptr();
Hasptr & operator= (const Hasptr &);
private:
string *ps;
size_t *use;
int i;
};
Hasptr::~Hasptr()
{
if (--*use == 0)
{
delete use;
delete ps;
}
}
Hasptr & Hasptr:: operator= (const Hasptr &h)
{
++*h.use;
if (--*use == 0)
{
delete ps;
delete use;
}
ps = h.ps;
i = h.i;
use = h.use;
return *this;
}
为一个二叉树定义一个行为像值的类.注意删除时候的顺序.
class TreeNode
{
public:
TreeNode() :left(nullptr), right(nullptr), count(0){}
TreeNode(const TreeNode &r) : left(new TreeNode(*r.left)), right(new TreeNode(*r.right)), value(r.value)
, count(r.count){}
TreeNode& operator= (const TreeNode & r)
{
auto temp_left = (new TreeNode(*r.left));
auto temp_right = (new TreeNode(*r.right));
delete left;
delete right;
left = temp_left;
right = temp_right;
value = r.value;
count = r.count;
}
~TreeNode(){ delete left; delete right; }
private:
string value;
int count;
TreeNode *left;
TreeNode *right;
};