条款十七: 在operator=中检查给自己赋值的情况
在赋值运算符中要特别注意可能出现别名的情况,其理由基于两点。其中之一是效率。如果可以在赋值运算符函数体的首部检测到是给自己赋值,就可以立即返回,从而可以节省大量的工作,否则必须去实现整个赋值操作。
另一个更重要的原因是保证正确性。一个赋值运算符必须首先释放掉一个对象的资源(去掉旧值),然后根据新值分配新的资源。在自己给自己赋值的情况下,释放旧的资源将是灾难性的,因为在分配新的资源时会需要旧的资源。
看看下面string对象的赋值,赋值运算符没有对给自己赋值的情况进行检查:
class string {
public:
string(const char *value); // 函数定义参见条款11
// ~string(); // 函数定义参见条款11
//
... string& operator=(const string& rhs); private:
char *data;
}; // 忽略了给自己赋值的情况
// 的赋值运算符
string& string::operator=(const string& rhs)
{
delete [] data; // delete old memory // 分配新内存,将rhs的值拷贝给它
data = new char[strlen(rhs.data) + ];
strcpy(data, rhs.data); return *this; // see item 15
}
现在可以知道,解决问题的方案是对可能发生的自己给自己赋值的情况先进行检查,如果有这种情况就立即返回。不幸的是,这种检查说起来容易做起来难,因为你必须定义两个对象怎么样才算是“相同”的。
一个确定对象身份是否相同的方法是用内存地址。采用这个定义,两个对象当且仅当它们具有相同的地址时才是相同的。这个定义在c++程序中运用更广泛,可能是因为它很容易实现而且计算很快,而采用值相等的定义则不一定总具有这两个优点。采用地址相等的定义,一个普通的赋值运算符看起来象这样:
c& c::operator=(const c& rhs)
{
// 检查对自己赋值的情况
if (this == &rhs) return *this; ... }
条款十七: 在operator=中检查给自己赋值的情况的更多相关文章
- Effective C++_笔记_条款11_在operator=中处理“自我赋值”
(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 为什么会出现自我赋值呢?不明显的自我赋值,是“别名”带来的结果: ...
- EC读书笔记系列之6:条款11 在operator=中处理自我赋值
记住: ★确保当对象自我赋值时operator=有良好行为.有三种方法:比较“来源对象”和“目标对象”的地址.精心周到的语句顺序.以及copy-and-swap技术 ★确定任何函数若操作一个以上对象, ...
- Effective C++ -----条款11: 在operator=中处理“自我赋值”
确保当对象自我赋值时operator=有良好行为.其中技术包括比较“来源 对象”和“目标对象”的地址.精心周到的语句顺序.以及copy-and-swap. 确定任何函数如果操作一个以上的对象,而其中多 ...
- 在operator =中要处理“自我赋值”
防止自我赋值很有必要 Widget w; w = w; a[i] = a[j]; //a[i]和a[j]实际上指向同一个元素 *pi = *pj; //pi和pj实际上指向同一个元素 自我赋值的危害: ...
- 编程中检查IIS7组件的安装情况
http://learn.iis.net/page.aspx/135/discover-installed-components/说明:ASP.NET网络应用程序在IIS7上部署的时候,经常会要求预装 ...
- 条款十六: 在operator=中对所有数据成员赋值
当涉及到继承时,派生类的赋值运算符也必须处理它的基类成员的赋值!否则,当派生类对象向另一个派生类对象赋值时,只有派生类部分赋值了.看看下面: class base { public: ): x(ini ...
- 条款11:记得在operator=中处理自赋值的情况。
本来的版本是这样的: Widget & Widget::operator=(Widget rhs) { delete pb;//这里可能直接将rhs的pb删除了 pb = new (*rhs. ...
- 条款八: 写operator new和operator delete时要遵循常规
自己重写operator new时(条款10解释了为什么有时要重写它),很重要的一点是函数提供的行为要和系统缺省的operator new一致.实际做起来也就是:要有正确的返回值:可用内存不够时要调用 ...
- 读书笔记 effective c++ Item 11 在operator=中处理自我赋值
1.自我赋值是如何发生的 当一个对象委派给自己的时候,自我赋值就会发生: class Widget { ... }; Widget w; ... w = w; // assignment to sel ...
随机推荐
- iOS---iPad开发及iPad特有的特技
iPad开发简单介绍 iPad开发最大的不同在于iPhone的就是屏幕控件的适配,以及横竖屏的旋转. Storyboard中得SizeClass的横竖屏配置,也不支持iPad开发. 1.在控制器中得到 ...
- eval()将json 字符串转换为数组
json ={ GW:[{id:"655",mc:"董事"},{id:"656",mc:"书记"},{id:" ...
- Linq详细介绍
声明----文档转载自:http://www.cnblogs.com/liulun/archive/2013/02/26/2909985.html 在说LINQ之前必须先说说几个重要的C#语言特性 一 ...
- MIPS的寄存器、指令和寻址方式的分类
MIPS的32个寄存器 助记符 编号 作用 zero 0 恒为0 at 1 (assembly temporary)保留给汇编器使用 v0,v1 2-3 (values)子程序返回,即函数调用时的返回 ...
- sh NonUniqueObjectException
话题引入: 使用hibernate进行更新操作时,首先调用了findById方法获取要修改的对象,此时session没有被关闭,接着重新创建一个对象,将要修改的属性值赋值给这个对象.调用修改方法抛出如 ...
- CREATE CONSTRAINT TRIGGER - 定义一个新的约束触发器
SYNOPSIS CREATE CONSTRAINT TRIGGER name AFTER events ON tablename constraint attributes FOR EACH ROW ...
- Oracle使用plsql连不上本地数据库,cmd中使用sqlplus连的上的可能解决方案
1.无监听程序 原因: 最有可能是oracle监听的服务没有启动起来. 2.ORA-12514 TNS 监听程序当前无法识别连接描述符中请求服务 原因: 1.服务没有配置127.0.0.1或监听程序没 ...
- jsencrypt加解密 &&cryptico
npm install --save jsencrypt import {JSEncrypt} from 'jsencrypt'; //导入公钥if ( publicKey.indexOf('---- ...
- 面向UI编程思想
UI编程思想: 模块化+组合 模块化是分解: 组合是合成: https://www.cnblogs.com/feng9exe/p/11044134.html
- ID字段不采用数据库自增长的几点理由
一个小程序,最初采用了 SqlServer 数据库,后来为了便于部署,转而采用了 Firebird 嵌入式数据库.在重构代码转到 Firebird 的过程中,对“数据实体的数据表的ID字段是否应该使用 ...