Effective C++之条款11、12

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

    “自我赋值”发生在对象被赋值给自己时:

class Widget {...};
Widget w;
...
w = w;            //赋值给自己

    这样的赋值在编译器看来是合法的。此外赋值动作可能并不明显,例如:

a[i] = a[j];       //潜在的自我赋值,如i=j
*px = *py;         //潜在的自我赋值,px和py指向同一个位置

    下面是赋值操作实现代码,表面上看起来合理,但自我赋值出现时并不安全。

Widget& Widget::operator=(const Widget& rhs) {
	delete pb;                  //删除当前使用的bitmap
	pb = new Bitmap(*rhs.pb);   //使用rhs.bitmap的副本
	return *this;
}

    上述问题出在自我赋值,即当rhs和*this指向同一个对象时,由于delete操作销毁了当前的bitmap,那么之后的操作便出现了问题,因为此时rhs指向一个已被删除的对象。

    解决这个问题可以这样做:

Widget& Widget::operator=(const Widget& rhs) {
	Bitmap* pOrig = pb;          //记住原先的pb
	pb = new Bitmap(*rhs.pb);    //令pb指向*pb的一个复件
	delete pOrig;                //删除原先的pb
	return *this;
}

    另一个可替代方案是,使用所谓的copy and swap技术。这个技术和“异常安全性”有密切关系,详见条款29详细说明。

class Widget {
...
void swap(Widget& rhs); //交换*this和rhs的数据,详见条款29
};
Widget& Widget::operator=(const Widget& rhs) {
	Widget tmp(rhs);   //为rhs数据制作一份附件(副本)
	swap(tmp);	       //将*this数据和上述复件的数据交换
	return *this;
}

    另一个变种方案利用以下事实:(1)某class的copy assignment操作符可能被声明为"以by value方式接受实参";(2)以by value方式传递东西会造成一份复件/副本。(这种做法并不最先推荐)

Widget& Widget::operator=(Widget rhs) { //rhs是被传对象的一份副本
                                        //注意这里是pass by value
	swap(rhs);                          //将*this的数据和复件/副本的数据互换                                  
	return *this;
}

请记住

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

条款12:复制对象时勿忘其每一个成分

    我们知道如果不声明copying函数,那么编译器会为我们生成“编译器版本”的copying函数,这些函数会将被拷贝对象的所有成员变量都做一份拷贝。 然而如果我们自己声明copying函数,那么可能会出现这样的错误,如:当我们需要在已有的类中添加一个新的成员变量时,这时候copying函数如果不做相应的修改,则无法对新的成员变量进行拷贝。

请记住

  • Copying函数应该确保复制“对象内的所有成员变量”及“所有base class成分”。
  • 不要尝试以某个copying函数实现另一个copying函数。应该将共同机能放进第三个函数中,并由两个copying函数共同调用。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值