类的赋值操作 使用 "复制-交换(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; }
转载于:https://blog.51cto.com/spikeking/1388027