EC读书笔记系列之6:条款11 在operator=中处理自我赋值
记住:
★确保当对象自我赋值时operator=有良好行为。有三种方法:比较“来源对象”和“目标对象”的地址、精心周到的语句顺序、以及copy-and-swap技术
★确定任何函数若操作一个以上对象,而其中多个对象是同一个对象时,其行为仍然正确
------------------------------------------------------------------------------------
潜在的自我赋值举例:
a[i] = a[j]; //若i和j相同,便是自我赋值
*px = *py; //若px和py恰巧指向同一个东西
这些潜在的自我赋值是别名(所谓别名就是有一个以上的方法指称某对象)带来的结果。实际两个对象只要来自于同一个继承体系,他们甚至不需要声明为相同类型就可能造成“别名”,∵一个base class的reference或pointer可以指向一个derived class对象。
举例:下面的operator=代码,表面合理,但自我赋值时不安全
class Bitmap {...};
class Widget {
...
private:
Bitmap *pb; //含有指针或引用的类在写copying函数时就要注意!本能!
};
Widget& Widget::operator=( const Widget& rhs ) {
delete pb; //停止使用当前的bitmap
pb = new Bitmap( *rhs.pb );
return *this;
}
上面存在的问题:*this和rhs有可能是同一个对象。这样delete就不只是销毁当前对象的bitmap,它也销毁rhs的bitmap。
解决方案一:比较“来源对象”和“目标对象”的地址(证同测试),经典解法,初级!!!
Widget& Widget::operator=( const Widget& rhs ) {
if( this == &rhs )
return *this; //证同测试,是自我赋值的话就不做任何事
delete pb;
pb = new Bitmap( *rhs.pb );
return *this;
}
此版可行,但仍存在异常方面的麻烦:若new Bitmap导致异常(有可能因为分配时内存不足或因为Bitmap的copy constructor抛出异常),Widget最终会持有一个指针指向一块被删除的Bitmap。
解决方案二:手工排列语句顺序
Widget& Widget::operator=( const Widget& rhs ) {
Bitmap *pOrig = pb; //记住原先的pb
pb = new Bitmap( *rhs.pb );
delete pOrig;
return *this;
}
这段代码好处有二:
异常安全: 若new Bitmap失败,pb保持原状;
避免自我赋值:∵对原Bitmap做了一份复件、删除原Bitmap、再指向新制造的那个复件。
此种方法可能不是最高效的办法!!!但行得通。
解决方案三:使用copy-and-swap技术
class Widget {
...
void swap( Widget &rhs ); //交换*this和rhs的数据,详见条款29
...
};
Widget& Widget::operator=( const Widget& rhs ) {
Widget temp( rhs ); //为rhs数据制作一份复件---此即copy
swap( temp ); //将*this数据和上述复件的数据交换--此即swap
return *this;
}
方案三还有个改进版:
Widget& Widget::operator=( Widget rhs ) { //注意这里是传值,∴rhs是被传对象的副本
swap( rhs ); //将*this数据和上述复件的数据交换
return *this;
}
此版将copying动作从函数本体内移至函数参数构造阶段可令编译器有时生成更高效的代码
一个面试题目:写出String类的赋值运算符
class string{
public:
string& operator=( string rhs ){
swap( rhs );
return *this;
}
void swap( string& rhs ){
std::swap( _data, rhs._data );
}
private:
char* _data;
}
EC读书笔记系列之6:条款11 在operator=中处理自我赋值的更多相关文章
- Effective C++ -----条款11: 在operator=中处理“自我赋值”
确保当对象自我赋值时operator=有良好行为.其中技术包括比较“来源 对象”和“目标对象”的地址.精心周到的语句顺序.以及copy-and-swap. 确定任何函数如果操作一个以上的对象,而其中多 ...
- 读书笔记 effective c++ Item 11 在operator=中处理自我赋值
1.自我赋值是如何发生的 当一个对象委派给自己的时候,自我赋值就会发生: class Widget { ... }; Widget w; ... w = w; // assignment to sel ...
- Effective C++_笔记_条款11_在operator=中处理“自我赋值”
(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 为什么会出现自我赋值呢?不明显的自我赋值,是“别名”带来的结果: ...
- 11——在operator=中处理自我赋值
在operator=函数中加一个测试: if(&rhs==this) copy and swap
- EC读书笔记系列之5:条款9、条款10
条款9 绝不在构造和析构过程中调用virtual函数 记住: ★在构造和析构期间不要调用virtual函数,∵这类调用从不下降至derived class ---------------------- ...
- EC读书笔记系列之2:条款4 确定对象被使用前已先被初始化
条款4:确定对象被使用前已先被初始化 记住: ★为内置对象进行手工初始化,因为C++不保证初始他们 ★构造函数最好使用初始化列表,而不要在构造函数本体内使用赋值操作.初始化列表列出的成员变量,其排列次 ...
- Effective C++ 条款11:在operator=中处理"自我赋值"
"自我赋值"发生在对象被赋值给自己时: class Widget { ... }; Widget w; ... w = w; // 赋值给自己 a[i] = a[j]; // 潜在 ...
- Effective C++ 条款11,12 在operator= 中处理“自我赋值” || 复制对象时不要忘记每一个成分
1.潜在的自我赋值 a[i] = a[j]; *px = *py; 当两个对象来自同一个继承体系时,他们甚至不需要声明为相同类型就可能造成别名. 现在担心的问题是:假如指向同一个对象, ...
- EC读书笔记系列之11:条款20、21
条款20 宁以pass-by-reference-to-const替换pass-by-value 记住: ★尽量以pass-by-reference-to-const替换pass-by-value.前 ...
随机推荐
- 第十一届GPCT杯大学生程序设计大赛完美闭幕
刚刚过去的周六(6月7号)是今年高考的第一天,同一时候也是GPCT杯大学生程序设计大赛颁奖的日子,以下我们用图文再回想一下本次大赛颁奖的过程. 评审过程的一些花絮<感谢各位评审这些天的付出!&g ...
- Bootstrap 简洁、直观、强悍、移动设备优先的前端开发框架,让web开发更迅速、简单。
http://v3.bootcss.com/ 从2.x升级到3.0版本 Bootstrap 3并不向后兼容Bootstrap v2.x.下面章节列出的内容可以作为从v2.x升级到v3.0的通用指南.如 ...
- cocos2d_android 瞬间动作
该文章所写的瞬间动作主要有CCFlipX,CCFlipY,CCHide,CCShow 当中CCFlipX是以Y轴为中心旋转,CCFlipY是以X轴为中心旋转,CCHide将精灵对象隐藏,CCShow将 ...
- 【最大流之EdmondsKarp算法】【HDU1532】模板题
题意:裸的最大流,什么是最大流,参考别的博客 运用复杂度最高的EK算法 O(M*N),模板来自紫书 #include <cstdio> #include <cstdlib> # ...
- WisDom .net 工作流设计流程
1.简单说明 工作流( Foundare WorkFlow)说白了就是工作流程的一些计算机模型,即将工作流程中的工作如何前后组织在一起的逻辑和规则在计算机中以恰当的模型进行表示并对其实施计 ...
- javascript的几种时间格式
1.当前系统区域设置格式(toLocaleDateString和toLocaleTimeString) 例子:(new Date()).toLocaleDateString() + " &q ...
- mysql错误号码:1129
mysql 错误号码1129: mysql error 1129: Host 'bio.chip.org' is blocked because of many connection errors; ...
- C#4 for循环 迭代法 穷举法应用
for()循环. 四要素: 初始条件,循环条件,状态改变,循环体. 执行过程: 初始条件--循环条件--循环体--状态改变--循环条件.... 注意:for的小括号里面分号隔开,for的小括号后不要加 ...
- 持续更新visual studio 命令、快捷键(原创)
“格式化代码” Ctrl + E + D “注释” Ctrl + E + C “取消注释” Ctrl + E + U “点代替空白” 编辑-高级-显示空白 快捷键 Ctrl + E + S
- html 中head显示 在标题栏里面的图片
在<head>标签里加<link rel="Shortcut Icon" href="你的ico图片地址" /> 一般标题栏里的图片是1 ...