Effective C++ Item 11:在operator= 中处理“自我赋值”

本文深入探讨了C++中Widget类的赋值运算符重载实现过程,包括解决自我赋值和异常安全问题的方法。通过引入自赋值检测、异常安全策略及copy-and-swap技术,确保了代码的健壮性和高效性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.普通的operator=函数的实现

给定以下的operator=的实现代码,我们可以对operator=重载的代码进行分析:

class Bitmap {
};
class Widget {
public:
	Widget & operator=(const Widget& cw) {
		delete pb;                         //删除当前对象
		pb = new Bitmap(*cw.pb);           //使用cw的元素构建新的Bitmap对象
		return *this;                      //返回指向当前对象的引用
	}
private
	Bitmap * pb;
};

上述代码有没有问题呢?

在operator=函数中,当参数cw引用指向的对象和函数内的*this是同一个对象时,delete操作不仅销毁了当前对象的bitmap,也销毁了参数cw的bitmap,函数结尾,this指针就指向了一个已被删除的对象

2.加入“自赋值检测”的operator=函数

为了避免因为自赋值导致的上述的状况,可以在赋值操作前进行自赋值检测,代码如下:

Widget & operator=(const Widget& cw) {
		if (&cw != this) {
			delete pb;                         //删除当前对象的bitmap指针
			pb = new Bitmap(*cw.pb);           //使用cw的元素构建新的Bitmap对象
		}
		return *this;                         //返回指向当前对象的引用
	}

进行“自赋值”检测的代码避免了上述因自赋值带来的安全问题,但还是存在“异常安全问题”。

具体的“异常安全问题”体现在在执行new Bitmap时,可能因为内存不够或调用Bitmap拷贝构造函数抛出异常。因此,Widget最终会持有一个指针指向一块被删除的Bitmap,这样的指针会带来太多的安全隐患:你无法安全删除它,甚至都读取不到它。剩下的唯一能做的事就是不断调试找到问题的根源。

3.加入“异常安全”的operator=函数

为了解决上述的异常安全问题,我们可保证在赋值pb所指东西前不要删除pb,具体可进行下面的操作:先将pb用变量保存,在pb被成功赋值后,再删除pb:

Widget & operator=(const Widget& cw) {
		Bitmap* oriBp = pb;                    //使用变量oriBp事先保存pb
		pb = new Bitmap(*cw.pb);               //在pb被成功赋值后
		delete oriBp;                          //再删除pb
		return *this;                         //返回指向当前对象的引用
	}

在这个解决方案中,如果“new Bitmap”操作中抛出异常,pb保持原状。

而且,这段代码也能处理自我赋值,因为对bitmap做了一份副本、删除原bitmap、然后指向新构造的那个副本。

4. “Copy and Swap”技术

为了提高上述既解决了“自我赋值”,又解决了“异常安全”问题的代码的效率,常用的“copy and Swap”技术就派上用场了,具体的实现代码如下:

class Bitmap {
};
class Widget {
public:
	void swap(Widget& cw);
	Widget & operator=(const Widget& cw) {
		Widget temp(cw);
		swap(temp);                            //将*this数据与上述复件的数据交换
		return *this;                         //返回指向当前对象的引用
	}
private:
	Bitmap* pb;
};

copy-and-swap技术和“异常安全性”有着密切联系,在《effective C++ Item 29》中对“异常安全性”做了详细解说。

《剑指offer》第二版的面试题一“赋值运算符函数”对于String类的赋值运算符重载的实现就是利用了“copy-and-swap”技术。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值