【11】在operator=中处理“自我赋值”
1、自我赋值,看起来愚蠢,但是却合法。有些自我赋值一眼就可看出来。有些自我赋值是潜在的。比如:a[i] = a[j]; *px = *py; 甚至不同类型的指针,都指向同一个地址,也是自我赋值,这一类自我赋值,很难识别,因此对自我赋值要有一定的防范。
2、对于资源管理类auto_ptr和shared_ptr,自我赋值是安全的。如果自行管理资源,比如Widget中有个Bitmap* pb;copy赋值如下:
Widget& Widget::operator=(const Widget& rhs)
{
delete pb;
pb = new Bitmap(*(rhs.pb));
return *this;
}
假如是自我赋值,delete销毁了this.pb,也是销毁了rhs.pb,rhs.pb指向垃圾,new出来的Bitmap也有问题。
3、怎么解决上面的问题,增加一个等同测试,如下:
Widget& Widget::operator=(const Widget& rhs)
{
if(this == &rhs)
{
return *this;
} delete pb;
pb = new Bitmap(*(rhs.pb));
return *this;
}
4、上面的方法还是有问题,考虑new Bitmap的时候出现异常,这种情况下,老的对象已经销毁,新的又没有分配成功,导致pb指向垃圾。怎么解决这个问题呢?
问题的关键是,先删除老的,再去分配新的。因此,可以这样解决:先把老的记录下来,再去分配新的,然后再去删除老的,如果分配新的出现异常,退出方法,老的没有删除,还是原来的值。如下:
Widget& Widget::operator=(const Widget& rhs)
{
if(this == &rhs)
{
return *this;
} Bitmap* old = pb;
pb = new Bitmap(*(rhs.pb));
delete old;
return *this;
}
5、再仔细分析一下,上面不需要等同测试,即使相同也是没有问题的,只不过导致Bitmap的copy构造。这种情况下,考虑等同测试的成本和Bitmap copy构造的成本,如果等同的频率很高,添加等同测试,否则去掉等同测试。
6、有没有更好的办法呢?
既然可能出现自我赋值,我可以先对rhs做个copy temp,然后this和temp交换,这样也就不需要考虑自我赋值了。特别注意:下面的交换只是交换指针值,并不交换指向的内容,可以认为是浅交换。
Widget& Widget::operator=(const Widget& rhs)
{
Widget temp(rhs);
swap(temp);
return *this;
}
7、上面的做法还可以优化,形参表中使用传值,方法内直接使用swap(rhs); 这种方法很好地利用了传值的特点,具有技巧性,但是失去了清晰性,不推荐这种做法。
【11】在operator=中处理“自我赋值”的更多相关文章
- 读书笔记 effective c++ Item 11 在operator=中处理自我赋值
1.自我赋值是如何发生的 当一个对象委派给自己的时候,自我赋值就会发生: class Widget { ... }; Widget w; ... w = w; // assignment to sel ...
- Effective C++ -----条款11: 在operator=中处理“自我赋值”
确保当对象自我赋值时operator=有良好行为.其中技术包括比较“来源 对象”和“目标对象”的地址.精心周到的语句顺序.以及copy-and-swap. 确定任何函数如果操作一个以上的对象,而其中多 ...
- EC读书笔记系列之6:条款11 在operator=中处理自我赋值
记住: ★确保当对象自我赋值时operator=有良好行为.有三种方法:比较“来源对象”和“目标对象”的地址.精心周到的语句顺序.以及copy-and-swap技术 ★确定任何函数若操作一个以上对象, ...
- 11——在operator=中处理自我赋值
在operator=函数中加一个测试: if(&rhs==this) copy and swap
- 条款11:在operator=中处理“自我赋值”
什么是自我赋值,就是 v = v 这种类型的语句,也许很多人都会说鄙视这种写法,但是如下的写法会不会出现呢? 比如:a[i] = a[j]; // 不巧的是i可能和j相等 *px = *py ...
- Effective C++ 条款11,12 在operator= 中处理“自我赋值” || 复制对象时不要忘记每一个成分
1.潜在的自我赋值 a[i] = a[j]; *px = *py; 当两个对象来自同一个继承体系时,他们甚至不需要声明为相同类型就可能造成别名. 现在担心的问题是:假如指向同一个对象, ...
- Effective C++ 条款11:在operator=中处理"自我赋值"
"自我赋值"发生在对象被赋值给自己时: class Widget { ... }; Widget w; ... w = w; // 赋值给自己 a[i] = a[j]; // 潜在 ...
- Effective C++_笔记_条款11_在operator=中处理“自我赋值”
(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 为什么会出现自我赋值呢?不明显的自我赋值,是“别名”带来的结果: ...
- [Effective C++ --011]在operator=中处理“自我赋值”
一.何谓“自我赋值”? 1.1.场合一 直接赋值 w = w; 1.2.场合二 同一数组 a[i] = a[j]: 1.3.场合三 指针 *px = *py: 1.4. ...
随机推荐
- bzoj1471
转化补集的思想,首先求出任意两点之间路径数目 然后求两条路径第一次相交在点k(按照拓扑排序的顺序)的数目,显然这里要用到容斥 然后pascal有坑爹的范围检测,所以运算中有些不会影响到答案但会爆int ...
- mvc源码解读(20)-controller和view之查找view
很多时候在mvc项目中我们需要去扩展自己的视图引擎,大概看起来应该下面这个样子的: public class RazorEngineExpand : RazorViewEngine { private ...
- BZOJ_1020_[SHOI2008]_安全的航线flight_(计算几何+二分)
描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1020 给出一条航线(折线),给出\(c\)个陆地(多边形).求航线上距离陆地的最近距离最远的距 ...
- android Bitmap getByteCount和getRowBytes
今天做图像缓存需要计算Bitmap的所占的内存空间,于是研究了下Bitmap关于内存占用的API 1.getRowBytes:Since API Level 1,用于计算位图每一行所占用的内存字节数. ...
- toastr
$(function(){ //参数设置,若用默认值可以省略以下面代 toastr.options = { "closeButton": false ...
- CF 55D - Beautiful numbers(数位DP)
题意: 如果一个数能被自己各个位的数字整除,那么它就叫 Beautiful numbers.求区间 [a,b] 中 Beautiful numbers 的个数. 分析:先分析出,2~9 的最大的最小公 ...
- Zabbix探索:网络设备监控2
在实现第一部分的简单监控的时候,在设置数据类型的时候设置成为了整数,结果: icmpping:这个没问题,只有0和1: icmppingloss:这个有问题,是百分比,其实是浮点数,单位是%: icm ...
- sizeof的作用——解释类中与类之外static变量的情况
今天看程序员面试宝典的时候遇到一个问题,书上有这么一句话:sizeof计算栈中分配的大小.咋一看这句话的时候,很不理解,难道像函数中类似于static.extern const类型的变量的sizeof ...
- POJ 1738 石子合并2 GarsiaWachs算法
石子合并(GarsiaWachs算法) 只能用该算法过!!! 详解看代码 //#pragma comment(linker, "/STACK:167772160")//手动扩栈~~ ...
- HDU 1024 DP Max Sum Plus Plus
题意:本题的大致意思为给定一个数组,求其分成m个不相交子段和最大值的问题. kuangbin专题. dp[i][j]=Max(dp[i][j-1]+a[j] , max( dp[i-1][k] ) + ...