读书笔记 ---- 在operator=中处理"自我赋值"

前言

最近在读《Effective C++》,对里面的思想和代码深有感触,因此在此做点记录并加以自己的理解,方便以后查看。
本文内容来自条款11:在operator=中处理"自我赋值"(Handle assignment to self in operator=.)

何谓自我赋值

考虑如下代码:

class A{...}
A a;
a = a;//赋值给自己

上述代码看起来不太可能出现,却是合法的,但这只是明显的自我赋值。潜在的自我赋值如下:
当i和j有相同的值时:a[i] = a[j];
当px和py指向同一个东西时:*px = *py;
以及函数参数中的多个对象是同一个的情况:

class A{...};
class B : public A{...};
void doSomething(const A& ra,B* pb);//rb和*pd有可能是同一个对象

另外,考虑如下代码:

class Bitmap{...};
class Widget{
	...
public:
	Widget& operator=(const Widget&);
private:
	Bitmap* pb;//指针,指向一个从heap分配来的对象
};

Widget& Widget::operator=(const Widget& rhs){
	delete pb;//停止使用当前的bitmap
	pb = new Bitmap(*rhs.pb);//通过拷贝构造函数来拷贝rhs的*pb对象
	return *this;
}

此处存在问题,如果rhs和*this是同一个对象,那么就会出现问题,在new Bitmap时,用到的rhs.pb指针指向的内容已经被销毁,因此这是隐含有安全问题的,也就是没有考虑自我赋值的影响。
这段代码隐含的问题是不具备自我赋值安全性异常安全性

解决方案之证同测试

传统的解决方案是做证同测试来达到自我赋值的检验目的:

Widget& Widget::operator=(const Widget& rhs){
	if(this == &rhs) return *this;//证同测试,如果是自我赋值,就什么也不做
	delete pb;
	pb = new Bitmap(*rhs.pb);
	return *this;
}

但这个方案只解决了自我赋值安全性,而仍然存在异常安全性问题:如果"new Bitmap"时抛出异常,pb最终会指向一块被删除的空间,很明显这样是有问题的。

解决方案之考虑异常安全性

让operator=具备"异常安全性"时,往往会自动获得"自我赋值安全性"。因此越来越多人对"自我赋值"的处理态度是不处理,而把焦点放到实现"异常安全性"上。因此,只需要注意在复制pb所指向的东西之前别删除pb:

Widget& Widget::operator=(const Widget& rhs){
	Bitmap *pOrig = pb;//记住原先的pb值
	pb = new Bitmap(*rhs.pb);
	delete pOrig;//删除原先的pb
	return *this;
}

这样或许不是处理"自我赋值"最高效的办法,但它同时兼顾了自我赋值安全性异常安全性

解决方案之"copy and swap"技术

跟上面的方法是一个道理,但这种方法与"异常安全性”密切相关,因此值得看看其实现手法。

  • 方式一:基于pass-by-reference的实现
    class Widget{
    	...
    	void swap(Widget& rhs);//交换*this和rhs的数据
    	...
    }
    
    Widget& Widget::operator=(const Widget& rhs){
    	Widget temp(rhs);//为rhs创建一份副本
    	swap(temp);//将*this的数据与temp的数据互换
    	return *this;
    }
    
  • 方式二:基于pass-by-value的实现
    class Widget{
    	...
    	void swap(Widget& rhs);//交换*this和rhs的数据
    	...
    }
    
    Widget& Widget::operator=(const Widget rhs){
    	//pass-by-value传参,本身就是一份副本
    	swap(temp);//将*this的数据与rhs的数据互换
    	return *this;
    }
    

总结

  • 确保当对象自我赋值时operator=有良好的表现。
  • 确保任何一个函数如果操作一个以上的对象,而其中多个对象是同一个对象时,其行为仍然正确。

参考文献

《Effective C++(第三版)》

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值