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.前 ...
随机推荐
- ASP.NET State Service
本文来自:http://www.cnblogs.com/jhxk/articles/1648194.html 这一段就是配置应用程序是如何存储Session信息的了.我们以下的各种操作主要是针对这一段 ...
- Hadoop CLI MiniCluster
CLI MiniCluster Use the climonicluster, users can simply start and stop a single-node hadoop cluster ...
- Android EditText限制输入一些固定字符的属性
android:digits="abcdefghijklmnopqrstuvwxyz1234567890" 仅仅能输入这些
- C# 泛型转换 将object[] 数组转换为泛型列表
public List<TaskSoftInfo> ReadSoftDownTaskList() { string[] Tid = (strin ...
- Android官方技术文档翻译——Ant 任务
本文译自Android官方技术文档<Ant Tasks>,原文地址:http://tools.android.com/tech-docs/ant-tasks. 由于是抽着时间译的.所以这篇 ...
- 【最大团】【HDU1530】【Maximum Clique】
先上最大团定义: 最大团问题(Maximum Clique Problem, MCP)是图论中一个经典的组合优化问题,也是一类NP完全问题,在国际上已有广泛的研究,而国内对MCP问题的研究则还处于起步 ...
- java 判断字符串编码
String iso8859 = new String(sb.toString().getBytes("iso8859-1"));String gbk = new String(s ...
- JavaScript 【跨浏览器处理XML,做个兼容】
//兼容方法 function getXMLDOM(xmlStr) { var xmlDom = null; if (typeof windo ...
- Android Service 系统服务
android sdk 提供很多公用的服务,也就是系统服务,开发者可以通过Activity类的getSystemService方法获取指定的服务.系统服务包含音频服务.视频服务窗口服务等.本篇主要讲T ...
- Ext.grid.GridPanel的属性
1.Ext.grid.GridPanel 主要配置项: store:表格的数据集 columns:表格列模式的配置数组,可自动创建ColumnModel列模 ...