翻译《有关编程、重构及其他的终极问题?》——35.给enum新增常量后不要忘了修改对应的switch操作

翻译《有关编程、重构及其他的终极问题?》——35.给enum新增常量后不要忘了修改对应的switch操作

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


35.给enum新增常量后不要忘了修改对应的switch操作

(译者注:我觉得这篇写的很勉强)

下面这段代码来自Appleseed项目。PVS-Studio分析诊断后,对于其中包含的错误做了如下描述:V719 The switch statement does not cover all values of the ‘InputFormat’ enum: InputFormatEntity(译者注:大意是switch没有包含InputFormat枚举中的所有值)。

enum InputFormat
{
    InputFormatScalar,
    InputFormatSpectralReflectance,
    InputFormatSpectralIlluminance,
    InputFormatSpectralReflectanceWithAlpha,
    InputFormatSpectralIlluminanceWithAlpha,
    InputFormatEntity
};

switch (m_format)
{
  case InputFormatScalar:
    ....
  case InputFormatSpectralReflectance:
  case InputFormatSpectralIlluminance:
    ....
  case InputFormatSpectralReflectanceWithAlpha:
  case InputFormatSpectralIlluminanceWithAlpha:
    ....
}

解释

有时候我们需要给存在的enum增加新的值,当我们这样做时,我们需要比较谨慎的处理——一般来说,我们需要在我们的代码中检查所有用到这个enum的地方,比如在每个switch和if块,其中一种情况就是上面代码示例的。

在enum类型InputFormat中添加新的常量InputFormatEntity——一般新增加的常量会被放置在最后,所以我假定如此。程序员经常把新增加的常量放到enum的末尾(译者注:作者有些啰嗦),但却忘了检查他们的代码,以使新增的常量在所有地方都能正常工作,包括也常忘了纠正switch操作块。

结果,我们可以看到,“m_format==InputFormatEntity”这种情况就没有被处理。

正确的代码

switch (m_format)
{
  case InputFormatScalar:
  ....
  case InputFormatSpectralReflectance:
  case InputFormatSpectralIlluminance:
  ....
  case InputFormatSpectralReflectanceWithAlpha:
  case InputFormatSpectralIlluminanceWithAlpha:
  ....
  case InputFormatEntity:
  ....
}

建议

让我们思考一下,如何才能通过代码重构来减少这些错误?最简单的方法但不是最优的方法就是在swtch块中增加一个“default:”,比如:

switch (m_format)
{
  case InputFormatScalar:
  ....
  ....
  default:
    assert(false);
    throw "Not all variants are considered"
}

现在,如果m_format变量值为InputFormatEntity,我们就会看到断言和异常。但这种方法有两个缺点:

  1. 这个错误有可能在测试中不出现(如果在测试中,m_format的值不为InputFormatEntity),这样这个错误就不会发现,从而留到了发布的版本。而在发布版本中,这个错误有可能会被发现——而且是在客户运行的时候发现。如果客户发现并报告的这个问题,这就尴尬了。

  2. 如果我们把default看作错误处理的一种,那么前面就不得不给每种enum的常量写一个case来对应,这就很不方便,要知道,有些枚举类型有很多很多常量值。有时候,用default处理一些不同的case值是很方便的。

我建议用下面的方法来解决这个问题——虽然我不能说这个方法有多好。你可以用一个关键字和枚举类型的名字。

比如:

enum InputFormat
{
  InputFormatScalar,
  ....
  InputFormatEntity
  //If you want to add a new constant, find all ENUM:InputFormat.
};

switch (m_format) //ENUM:InputFormat
{
  ....
}

在上面的代码中,当你修改了InputFormat枚举类型的内容时,你可以在项目的源代码中直接朝朝“ENUM:InputFormat”。

如果你在一个研发人员的team中,你最好让每个人都知道这个约定,并且把这个约定写道你的code style规范中。如果谁没有遵守这个约定,那就太不幸了。

猜你喜欢

转载自blog.csdn.net/headman/article/details/81176076
今日推荐