条款11:在operator=中处理”自我赋值“

(一)有别名的存在,所以有可能自我赋值。

下面的代码不具备自我赋值的安全性 也不具备 异常安全性

class Bitmap {...};
class Widget {
	...;
private:
	Bitmap* pb;
};

Widget& Widget::operator=(const Widget& rhs) {   //一份不安全的operator=实现版本
	delete pb;
	pb = new Bitmap(*rhs.pb);
	return *this;
}

自我赋值的话, 调用的对象和传入的参数是同一个对象,*this 跟rhs是同一个对象。那么delete pb,那么唯一的对象就被销毁了。

在函数末尾,该对象pb发现自己持有的是一个指针指向一个已被删除的对象。


阻止这种错误的方法是(在赋值函数前面加一个”正同测试“)

class Bitmap {...};
class Widget {
	...;
private:
	Bitmap* pb;
};

Widget& Widget::operator=(const Widget& rhs) {   //一份不安全的operator=实现版本
	delete pb;
	pb = new Bitmap(*rhs.pb);
	return *this;
}
具备”自我赋值安全性“ 却不具备”异常安全性“。如果new Bitmap导致异常(无论new 内存或者copy)Widget最终会持有一个指针指向一块被删除的BItmap

解决这个问题的方法(处理 异常安全性的同时也处理自我赋值安全性)

我们只注意在复制pb所指东西之前别删除 pb。代码:

Widget& Widget::operator=(const Widget& rhs) {   //一份很安全的operator=实现版本
	Bitmap* pOrig = pb;
	pb = new Bitmap(*rhs.pb);
	delete pOrig;
	return *this;
}

如图:

如果Bitmap出现异常,pb以及它所指的对象都会保持原状。

也可以自我赋值,当自我赋值的时候,如上图,pb指向原对象的一个副本。删除原bitmap。返回原对象的副本。同样实现了自我赋值。


(三)还有一个更好的方法使我们operator=函数不仅具有”自我赋值“而且”异常安全“。这就是copy and swap 没有new delete的困扰了

class Widget {
	...;
	void swap(Widget& rhs);    //交换*this和rhs的数据。
	...;
};
Widget& Widget::operator=(const Widget& rhs) {
	Widget temp(rhs);  //为rhs数据制作一份副本
	swap(temp);        //将*this数据和上述复件的数据交换。
	return *this;
}

也可以const reference 为参数。还可以pass by value方式

Widget& Widget::operator=(Widget rhs) {
	swap(rhs);        //将*this数据和上述复件的数据交换。
	return *this;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值