翻译《有关编程、重构及其他的终极问题?》——15.在你的代码中开始使用enum class吧

翻译《有关编程、重构及其他的终极问题?》——15.在你的代码中开始使用enum class吧

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


15.在你的代码中开始使用enum class吧

抱歉,所有我这里关于这个问题的例子都很大,所以我选择了一个最小的,其实还是有些大。

这个bug实在Source SDK库中发现的。PVS-Studio是这样描述这个问题的:V556 The values of different enum types are compared: Reason == PUNTED_BY_CANNON(译者注:大意是说来自不同enum中的值被比较了)。

enum PhysGunPickup_t
{
  PICKED_UP_BY_CANNON,
  PUNTED_BY_CANNON,
  PICKED_UP_BY_PLAYER,
};

enum PhysGunDrop_t
{
  DROPPED_BY_PLAYER,
  THROWN_BY_PLAYER,
  DROPPED_BY_CANNON,
  LAUNCHED_BY_CANNON,
};

void CBreakableProp::OnPhysGunDrop(...., PhysGunDrop_t Reason)
{
  ....
  if( Reason == PUNTED_BY_CANNON )
  {
    PlayPuntSound(); 
  }
  ....
}

解释
Reason变量是一个PhysGunDrop_t的enum类型,而与这个变量做比较的常量PUNTED_BY_CANNON却属于另外一个enum类型,所以很明显这是一个逻辑错误。

这个bug非常常见,我甚至无意中在如下项目中发现类似bug:Clang,TortoiseGit,and Linux Kernel。

这个bug如此常见的原因是因为在标准C++中enum类型不是类型安全的,所以你可能很容易就混淆那些是可以比较的。

正确的代码
我们无法确定这段代码正确的版本是怎样的。我猜PUNTED_BY_CANNON应该可以被DROPPED_BY_CANNON或者LAUNCHED_BY_CANNON替换。我们这里就用LAUNCHED_BY_CANNON吧。

{
  PlayPuntSound(); 
}

建议
如果你使用C++,你应该决定幸运。我建议你马上就开始使用enum class吧(译者注:C++11标准中出现的,大多数编译器都支持),那样的话编译器不会让你比较来自不同enum类型的值。你就不再会比较磅和寸了。

有一些C++的创新我不是很有信心。比如auto关键字,我相信如果使用太多的话反而会不好,因为我觉得:程序员们其实在阅读代码时花费的时间要比写代码还多,所以我们必须要保证代码容易读。在C语言中,变量在函数的开头定义,所以当我们在代码中间或者结尾编辑做修改时,不太容易一下子发现类似Alice变量意味着什么这样这类的问题,所以就有了变量命名的一个规则方式。比如,有前置规则,这样pfAlice可能就表明是一个“指向浮点的指针”。

在C++中,你可以随意声明你的变量并且这样是被认可的好方式。但继续使用前置或后置规则命名变量却不再流行。然后,auto关键字又出现了,导致了编程时各种神秘的结构又出现了,比如:“auto Alice = Foo();”,谁他妈的知道Alice适合呢么?!(译者注:这里作者有F**k的字眼,我就贴近的翻译了)。

抱歉离题了,我只是想顺便给你说下语言的新特性可能同时意味着好和不好,但这不适用于enum class:我相信这个新特性只意味着好。

当我们使用enum class时,你必须清晰的指定某一常量属于哪一个enum类型,这就防止了代码出现之前提到的问题。使用enum class后,代码如下:

enum class PhysGunDrop_t
{
  DROPPED_BY_PLAYER,
  THROWN_BY_PLAYER,
  DROPPED_BY_CANNON,
  LAUNCHED_BY_CANNON,
};

void CBreakableProp::OnPhysGunDrop(...., PhysGunDrop_t Reason)
{
  ....
  if( Reason == PhysGunDrop_t::LAUNCHED_BY_CANNON )
  {
    PlayPuntSound(); 
  }
  ....
}

的确,修改旧的代码不容易,但我强烈建议从今天起在你的代码中开始使用enum class类型,你的代码将会受益。

这里我没有对enum class做更多的介绍,所以这里有一些链接,可以方便你学习C++ 11中这个不错的特性中的所有的细节:
1. Wikepedia C++11:Strongly typed enumerations
2. Cppreference:Enumeration declaration
3. StackOverflow:Why is enum class prefered over plain enum

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值