类的赋值操作 使用 "复制-交换(copy and swap) 技术" 详解

 

本文地址: http://blog.youkuaiyun.com/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;  }