类的赋值操作 使用 "复制-交换(copy and swap) 技术" 详解
本文地址: http://blog.csdn.net/caroline_wendy/article/details/14645603
如果不包含动态内存分配, 则可以不用设置, 使用合成构造器即可;
如果包含, 则需要自己定义复制-赋值构造器((copy-assignment constructor);
以下三种方法都是 基于 包含动态内存分配,且不使用智能指针(shared_ptr);
1. 使用临时变量方法
类的复制-赋值操作(copy-assignment operator), 是复制(copy)操作和析构(destruct)操作的集合;
ClassA& ClassA::operator= (....): 首先把"="右边的值复制到"="左边, 然后析构"="左边的值;
为了保证可以自赋值(self-assignment), 需要使用临时变量存储, 再删除对象;
代码如下:
//std::string *ps; ps(new std::string(s));
HasPtr& HasPtr::operator= (const HasPtr &rhs)
{
auto newp = new std::string( *(rhs.ps) );
delete ps;
ps = newp;
i = rhs.i;
return *this;
}
2. 使用计数器(counter)方法
使用计数器(counter)为了使类的操作, 可以像指针一样传递地址;
当不使用"shared_ptr"时,必须使用计数器(counter), 判断使用对象的指针数;
使用计数器时, 赋值操作则可以判断计数器的值, 来确定是否删除对象;
自赋值(self-assignment)问题的存在, 所以对于计数器应该 先加后减;
代码如下:
//std::string *ps; ps(new std::string(s));
//std::size_t *use; use(new std::size_t(1));
HasPtr& HasPtr::operator= (const HasPtr &rhs)
{
++(*(rhs.use)); //括号可以不用添加, 添加是为了清晰
if (--(*use) == 0) {
delete ps;
delete use;
}
ps = rhs.ps;
i = rhs.i;
use = rhs.use;
return *this;
}
3. 使用复制-交换(copy-swap)方法
复制-交换(copy-swap)方法是利用交换左右两侧的值, 达到赋值的目的;
可以处理自赋值(self-assignment)和异常安全(exception safe);
把自赋值问题交给交换(swap)方法; 把异常安全问题交给复制构造器(copy constructor);
注意: 赋值构造器 改变为 只传递实值(value), 不传递常量引用(const &);
使用"using std::swap"的目的是, 如果包含自定义的swap()函数, 则优先使用自定义的swap()函数; 如果未包含, 系统使用标准库的swap()函数;
代码如下:
HasPtr& HasPtr::operator= (HasPtr rhs) {
using std::swap;
swap(*this, rhs);
return *this;
}