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

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

**Handle assignment to self in operator= **

  1. 自我复制发生在对象被赋值给 自己时,这听起来很荒谬但是请注意,这是合法的。
class Widget{...};
Widget w;
...
w=w//易于识别的自我赋值

//潜在的自我赋值
a[i]=a[j]//如果i=j

//潜在的自我赋值
*px=*py;//如若px,py指向同一个对象
  1. 这些不明显的自我赋值往往是“别名”带来的结果。所谓别名就是有一个以上的方法指称(涉及)某对象。
//一般而言指针和引用会带来上述问题
//但实际上只要两个对象来自一个继承体系
//甚至不需要声明为相同类型,就可能造成“别名”
class Base{...};
class Drived:public Base{...};
//rd和pd有可能其实是同一对象。
void doSomething(const Base& rb,Drived* pd);
  1. 注意自我赋值的安全使用,防止“在停止使用资源之前就意外释放了他”的陷阱。
//假设你建立一个类,用来保存一个指针指向一块动态分配的位图
class Bitmap{...};
class Widget{
...
private:
	Bitmap* pd;
};
//下面是operator=实现代码
//表面上看起来安全,但是在自我赋值出现时并不安全。
//一份不安全的operator=实现版本
Widget& Widget::operator=(const Widget& rhs){
	delete pd;//停止使用当前的bitmap
	pd = new Bitmap(*rhs.pb);//使用rhs's bitmap的副本
	return *this;//见条款10
}
//这里的自我赋值问题是operator=两边可能是同一个对象。
//若真是如此,该函数返回了一个指针指向了一个不存在的对象

//预防止这种错误,传统方法是“证同测试”
//达到是否是“自我赋值”的检验目的
Widget& Widget::operator=(const Widget& rhs){
	//如果是“自我赋值”就什么也不做
	if(this == &rhs)return *this;//证同测试
	delete pd;
	pd = new Bitmap(*rhs.pb);
	return *this;//见条款10
}
//这么做行得通
//但是如果Bitmap分配内存时出问题,依然会导致上述问题
//即Widget拥有一个野指针,而你却无法处理这个野指针
  1. 许多时候一些精心安排的语句就可以导出异常安全(以及自我赋值安全)的代码。
Widget& Widget::operator=(const Widget& rhs){
	Bitmap *pOrig=pd;//记住原先的pd
	pd = new Bitmap(*rhs.pb);//令pd指向*pd的副本
	delete pOrig;//删除原先的pd
	return *this;//见条款10
}
//现在即使new Bitmap时抛出异常,
//pd以及他栖身的Widget会保持原状,因为我们有备份
//该方法或许不是效率最高的方法但是行得通

//copy and swap 技术
class Widget{
...
	//交换*this与rhs的数据
	void swap(Widget& rhs);
...
};
Widget& Widget::operator=(const Widget& rhs){
	Widget tmp(rhs);//为rhs制作一份副本
	swap(temp);//将*this与上述副本的数据交换
	return *this;
}

请记住

1. 确保当对象自我赋值时operator=有良好的行为。其中技术包括比较“来源对象和目标对象”的地址,精心周到的语句顺序,以及copy and swap 技术。
2. 确定任何函数如果操作一个 以上的对象,其中多个对象如果是一个对象的时,其行为仍然正确。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值