【问题标题】:if statement code style with returns带有返回的 if 语句代码样式
【发布时间】:2013-06-14 13:44:35
【问题描述】:

假设我有这个功能:

inline bool fileExists(const char *name) {
  FILE *file;
  if (fopen_s(&file, name, "r") == 0)
  {
    fclose(file);
    return true;
  } else {
    return false;
  }
}

上面那个好还是这个更好?

inline bool fileExists(const char *name) {
  FILE *file;
  if (fopen_s(&file, name, "r") == 0)
  {
    fclose(file);
    return true;
  }

  return false;
}

编译时有区别吗?

【问题讨论】:

  • 不,生成的代码将与任何体面的编译器(在发布版本中)完全相同。一个糟糕的编译器可能会为 else 分支发出一个额外的跳转。
  • 可能会有细微差别,但你不会注意到,这里说的是纳秒。

标签: c++ if-statement coding-style styles return


【解决方案1】:

这主要是见仁见智。 IMO 第二种形式更好,因为它总是提供返回值。如果您修改函数以在 else 子句中执行不同的操作,您可能会忘记添加返回值。在上面的示例中,生成的代码是相同的。

【讨论】:

    【解决方案2】:

    效率不是问题,不是。一个半体面的编译器会知道该怎么做。而对于这个简单的功能,逻辑上应该是一样的。但是对于更大的函数,逻辑更多,第二个稍微好一点,因为它保证函数总是返回。

    要么这样,要么更喜欢单点返回(这不一定适用于这里,因为函数相对较小)。这可以帮助编译器生成更好、更高效的代码,在某些情况下(多个返回语句会阻碍 RVO):

    inline bool fileExists(const char *name) {
      FILE *file;
      bool exists = false;
      if (fopen_s(&file, name, "r") == 0)
      {
        fclose(file);
        exists = true;
      }
      return exists;
    }
    

    【讨论】:

    • 尽管多年来一直提倡“单点返回”,但我认为(而且 AFAICT 我不是唯一一个)它通常会通过增加缩进级别和保持变量来降低可读性范围太长。我倾向于“提前返回”(就像在 OP 的第二个 sn-p 中所做的那样),即在函数开始时摆脱不寻常的路径,然后继续执行主要行为。不过,关于 RVO 的争论仍然存在。
    • @LucTouraille 这当然是个案情况。我不喜欢“总是”规则。
    【解决方案3】:

    不,编译器的语义分析,以及之后的优化器,都会产生相同的目标代码。

    【讨论】:

      【解决方案4】:

      在这种特殊情况下,绝对不是问题。 fopen 将花费几微秒(除非包含实际文件的目录没有被缓存,在这种情况下它是几毫秒),并且您担心是否有额外的跳转 - 这可能是 4-6 个时钟周期。

      一般来说,我更喜欢“一个返回声明”,但它有时会变得很混乱,在这种情况下,我更喜欢你的第二个选项。几乎总是,代码会变成这样,因为“编译器”也更喜欢单个退出点:

      bool fileExists(const char *name) {
        FILE *file;
        bool ret_val;
        if (fopen_s(&file, name, "r") == 0)
        {
          fclose(file);
          ret_val = true;
          goto end;
        }
        ret_val = false
      end:
        return ret_val;
      }
      

      有时,如果代码非常复杂——尤其是如果代码“一开始很简单”然后变得复杂,编译器会从一个函数获得多个返回点,但上述情况是相当典型的。 [我不建议你在代码中使用goto'。编译器完全有能力发挥作用]

      哦,我怀疑在这种情况下使用 inline 并不会对性能产生太大影响。

      【讨论】:

      • 内联可以在那里防止多个定义。
      • 当然,但我也认为将它放在标题中没有多大意义 - 与实际打开文件的开销相比,使其内联的节省很少 - 大概如果它发生冲突在系统中使用另一个名称,我们应该使用不同的名称。
      • Ops,我忘记了静态内联...我的函数只存在于一个 .cpp 文件中。
      • 如果它是静态的,那么无论你做什么,编译器都会决定是否内联它[禁止使用“-fno-inline”或类似的编译器选项]
      猜你喜欢
      • 2016-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-29
      • 1970-01-01
      • 2011-07-04
      • 2013-01-05
      • 2012-10-29
      相关资源
      最近更新 更多