翻译《有关编程、重构及其他的终极问题?》——25.不要再用this指针和nullptr比较了

翻译《有关编程、重构及其他的终极问题?》——25.不要再用this指针和nullptr比较了

标签(空格分隔): 翻译 技术 C/C++
作者:Andrey Karpov
翻译者:顾笑群 - Rafael Gu
最后更新:2017年05月22日


25.不要再用this指针和nullptr比较了

这段代码摘自CoreCLR项目。PVS-Studio对这段危险的代码诊断如下:V704 ‘this == nullptr’ expression should be avoided - this expression is always false on newer compilers, because ‘this’ pointer can never be NULL(译者注:大意是应该避免“this == nullptr”这种比较,因为“this”指针不可能为NULL,所以这个表达式始终返回false)。

bool FieldSeqNode::IsFirstElemFieldSeq()
{
  if (this == nullptr)
    return false;
  return m_fieldHnd == FieldSeqStore::FirstElemPseudoField;
}

解释
过去大家经常用this指针和0/NULL/nullptr进行比较,在早期的C++发展阶段,这种方式是比较常见的情况,我们已经在“考古”的研究中(译者注:作者把对老代码的研究比喻成考古)常发生这种情况,关于这些,我建议大家可以从这篇关于checking Cfront的文章中读到,因为在那些日子里,this指针的值是可以被改变的,但因为太久远了,我们都忘了这点。

让我们回到用this指针和nullptr比较中。

现在,这种比较是不合法的,因为根据现代的C++标准,this指针是不可能等于nullptr的。

根据正式的C++标准,对于this指针为空指针的方法IsFirstElemFieldSeq()的调用会导致不可预知的行为。

看上去如果this == 0,那么当这个方法被执行的时候,就无法对这个类的字段进行访问了。但在实际中有两个可行的、但不太好的方法可以让这些代码得到执行。根据C++标准,this指针不可能为null,所以编译器可以优化对这个方法的调用,简化成如下的方式:

bool FieldSeqNode::IsFirstElemFieldSeq()
{
  return m_fieldHnd == FieldSeqStore::FirstElemPseudoField;
}

顺便说一下,这里有个陷阱,假设我们有如下的继承结构:

class X: public Y, public FieldSeqNode { .... };
....
X * nullX = NULL;
X->IsFirstElemFieldSeq();

假设Y的类大小为8个字节,然后对于NULL(0x00000000)的原指针,将被矫正为指向FieldSeqNode子对象实例的开始,这样,你就不得不使之偏移sizeof(Y)个字节。这样的话,在IsFirstElemFieldSeq()函数中的this值就被矫正为0x00000008了,那么“this == 0”检查就彻底失去了其意义。

正确的代码
实际上很难给出一个正确代码的示例,只是仅仅从函数中移除判断条件是不够的。你必须进行代码重构来保证从来不会用空指针来调用这个函数。

建议
所以,现在“if (this == nullptr)”虽然过时了,但你还是能在很多应用和库中经常看到类似的代码(MFC库就是一个例子)。这也就是为何Visual C++还是依旧努力的在用this指针和0比较。我猜这是因为编译器开发者还没有疯狂到要把已经正常工作了10多年的代码移除掉。

但规则已经确定了,所以让我们开始避免用this指针和null比较吧。并且,一旦你有空闲时间,检查所有的不合法比较并且重写它们是非常有用的。

编译器在很大程度上应该按照下面的方式工作:开始它们会给出这些比较的警告作为过渡(也许现在已经这么做了,我没有研究过这个问题);然后在某一时刻他们将会全面的支持新标准,这样你的代码(译者注:如果有前述比较的话)就会一起停止工作。所以我强烈建议你开始遵照新的规定,这在以后会很有帮助。

P.S. 当重构时,你也许需要Null object patter

关于这个话题额外的链接:
1. 仍然在使用this指针和Null比较
2. V704诊断

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值