Guru of the Week 条款11:对象等同(Object Identity)问题

原创 2001年10月24日 08:44:00

GotW #11 Object Identity

著者:Herb Sutter     

翻译:kingofark

[声明]:本文内容取自www.gotw.ca网站上的Guru of the Week栏目,其著作权归原著者本人所有。译者kingofark在未经原著者本人同意的情况下翻译本文。本翻译内容仅供自学和参考用,请所有阅读过本文的人不要擅自转载、传播本翻译内容;下载本翻译内容的人请在阅读浏览后,立即删除其备份。译者kingofark对违反上述两条原则的人不负任何责任。特此声明。

Revision 1.0

Guru of the Week 条款11:对象等同(Object Identity)问题<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

难度:5 / 10

(“我到底是谁?”这个问题蕴含着如何确定两个指针是否真的指向同一个对象的问题)

 

[问题]

测试语句“this != &other 是一个防止自赋值(self-assingment)的常见编码手法。那么,要到达这个“防止自赋值(self-assingment)”目的,现有的语句是否是必要的和/或充分的呢?为什么?或者为什么不?如果答案是否定的,你又如何进行修改呢?注意要区分“protecting against Murphy vs. protecting against Machiavelli”。(* 译注:见本条款末尾)

    T& T::operator=( const T& other ){

        if( this != &other ) {  // the test in question

            // ...

        }

        return *this;

    }

 

[解答]

一个简短的解答:从技术上来看,它既不是必要的也不是充分的。在实践当中,它工作得颇好但也有可能在C++标准中被修改。

 

 * 论点:异常-安全(Murphy

     如果operator=()是异常-安全的(exception-safe),那么你并不需要检查自赋值(self-assignment)。这里有两个效率上的不利因素:a)如果可以进行自赋值(self-assignment)检查的话,那就可以进行彻底的优化从而省略掉赋值操作;b)如果代码被写成异常-安全的(exception-safe),那么同时也使得代码损失了一部分效率(这也即是说“paranoia has a price principle”,意即“偏执狂也有权衡代价的原则”)。

 

* 不是论点的论点:多重继承

过去曾有人把多重继承与本条款讨论的问题联系起来,但实际上这个问题与多重继承没有任何关系。我们的讨论的是一个涉及到C++标准怎样让你比较两个指针的技术性问题。

 

* 论点:运算符的重载(Machiavelli

虽然一些类可能会提供它们自己的operator&(),但是问题中对自赋值(self-assignment)的检查却很可能不如你所期望的那样运作,而是做一些完全不同的事情。用“protecting against Machiavelli”来意寓这种情况是因为,我们只能推测编写operator=()的人也许大概知道他实现的类是不是也重载了operator&()

要注意,一个类可能也会提供一个T::operator!=(),但这与本问题无关——它并不影响我们对自赋值(self-assignment)的检查,原因是:由于一个被重载的运算符至少有一个参数的类型必须是“类(class)”类型,因而我们不可能编写一个包含有两个T*型参数的T::operator!=()

 

后记1

下面是一个所谓的“笑话代码(code joke)”。信不信由你,竟然真有一些并无恶意但无疑是被误导了的代码编写者曾企图使用这样的代码:

 T::T( const T& other ) {

   if( this != &other ) {

      // ...

   }

}

 怎么样?你能第一眼就看出毛病吗?

 

后记2

       值得注意的是,还有另外一些情况,在这些情况当中,指针的比较也不是多数人光凭直觉就能考虑周到的。比如:

1.  James Kanze指出,把指针比较成字符串的行为是未定义的。其原因(我还未见有人给出过)是C++标准明确规定:允许编译器将字符串存放在重叠的内存区域以作为一种空间优化方案。

2.  一般来说,虽然像诸如<<=>>=等内建(built-in)运算符的运算结果在各种特定情况下(比如,同一个数组中的两个指向对象的指针)都有着良好的定义,但你还是不能用这些运算符对任意的指针进行比较。标准库的使用也是基于这种限制的,其中规定:less<>以及其它库函数必须给出各指针的次序(ordering),以使得我们可以创建,比方说,一个key为指针类型的map,即map<T*,U,less<T*>>。(译注:此处的mapSTL的一部分,一个map包括keyvalue两部分,使用的时候需要#include <map>

 

* 译注:关于MurphyMachiavelli,侯捷先生在其系列书评的《C++/OOP大系》中提到:“就我的英文程度而言,[Sutter99](即《Exceptional C++》)读起来不若[Meyers96] (即《More Effective C++》)和[Meyers98] (即《Effective C++2/e》)那般平顺,原因是其中用了很多厘语、口语、典故。举个例子,Morphy law是什麽,大家知道吗?(莫菲定律说:会出错的,一定会出错。)Machiavelli又代表了什麽意思?(意大利政治家,以诈术闻名。)”

在这里,本条款的译者kingofark只能惭愧的说kingofark自己也没有完全理解本条款使用MurphyMachiavelli两个词的用意。

Machiavelli:马基雅维利,尼克尔1469-1527意大利政治理论家,他的著作 君主论(1513)阐述了一个意志坚定的统治者不顾道德观念的约束如何获得并保持其权力;马基雅弗利,意大利新兴资产阶级思想政治家,历史学家。)

对象的序列化与反序列化---IO学习笔记(四)

对象的序列化,反序列化 对象的序列化: 就是将Object转换成byte序列 对象的反序列化: 将byte序列转换成Object序列化流,反序列化流 序列化流(ObjectOutputStr...
  • u013991521
  • u013991521
  • 2015年08月13日 11:36
  • 896

mysql的week函数与JAVA计算周的差别问题

1、问题: 在某些情况下,会需要将日期按周来进行排序或统计,mysql就要用到week()或yearWeek()函数,就会发现,比如2016年的某一天,在mysql里面是属于第30周,但在JAVA中使...
  • cwfreebird
  • cwfreebird
  • 2017年01月22日 15:06
  • 1214

《Effective C++》资源管理:条款13-条款15

在系统中,资源是有限的,一旦用完必须归还给系统,否则可能会造成资源耗尽或其他问题。例如,动态分配的内存如果用完不释放会造成内存泄漏。 这里说的资源不仅仅是指内存,还包括其他,例如文件描述符、网络连接、...
  • KangRoger
  • KangRoger
  • 2015年01月14日 21:46
  • 1283

Java装箱==的池化坑

“基本类型优于装箱基本类型” ,其中那个Integer例子觉得不合适,于是看了Integer源码,发现还真是有点问题,至少我的jdk1.7是有问题的。 Java是高度封装基于JVM API的...
  • xj2419174554
  • xj2419174554
  • 2016年01月30日 12:46
  • 414

windows下用eclipse+goclipse插件+gdb搭建go语言开发调试环境

windows下用eclipse+goclipse插件+gdb搭建go语言开发调试环境 目前go语言在window或者linux操作系统上,最好的go语言开发调试环境都是由eclipse+goc...
  • manlyboy1
  • manlyboy1
  • 2016年07月28日 10:27
  • 4239

探讨SQL Server并发处理存在就更新七种解决方案

探讨SQL Server并发处理存在就更新七种解决方案 前言 本节我们来讲讲并发中最常见的情况存在即更新,在并发中若未存在行记录则插入,此时未处理好极容易出现插入重复键情况,本...
  • xxdddail
  • xxdddail
  • 2017年06月01日 08:54
  • 531

JS对象Object的常用方法汇总

//Object.assign函数 //将来自一个或多个源对象中的值复制到一个目标对象 var first = {name : 'kong'}; var last = {age : 18}; var ...
  • kongjunchao159
  • kongjunchao159
  • 2017年04月11日 15:06
  • 762

打印object对象

一般情况在测试js时,如果接口返回的数据是object对象。 如果不知道这个对象里面具体的属性就取值容易得到undefined。 哪么怎么知道一个object对象里面到底是什么东西呢。 答案就是...
  • yaerfeng
  • yaerfeng
  • 2014年09月19日 18:41
  • 3743

SQL SERVER中利用IDENTITY属性创建自动ID列

DENTITY(属性) 在表中创建一个标识列。该属性与 CREATE TABLE 及 ALTER TABLE Transact-SQL 语句一起使用。 说明  IDENTITY 属性与 SQL-D...
  • yinghuolsx
  • yinghuolsx
  • 2017年04月26日 15:00
  • 703

App Store审核条款(2016.06.21更新)

App Store 审核条款
  • bb1223
  • bb1223
  • 2016年06月21日 14:33
  • 1708
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Guru of the Week 条款11:对象等同(Object Identity)问题
举报原因:
原因补充:

(最多只允许输入30个字)