【问题标题】:What does “warning: not all control paths return a value” mean? (C++)“警告:并非所有控制路径都返回值”是什么意思? (C++)
【发布时间】:2018-03-18 14:29:00
【问题描述】:

我得到的确切警告是

warning C4715: "spv::Builder::makeFpConstant": not all control paths return a value

spv::Builder::makeFpConstant

Id Builder::makeFpConstant(Id type, double d, bool specConstant)
{
        assert(isFloatType(type));

        switch (getScalarTypeWidth(type)) {
        case 16:
                return makeFloat16Constant(d, specConstant);
        case 32:
                return makeFloatConstant(d, specConstant);
        case 64:
                return makeDoubleConstant(d, specConstant);
        }

        assert(false);
}

谁能帮帮我?

【问题讨论】:

  • 这意味着您的函数需要返回,但在某些情况下您的程序可能会采取最终没有返回的路线
  • 您当前的构建设置可能会禁用assert
  • 断言是“这不应该发生”。它是一种省力的合约,在运行时进行检查,并且(通常)从生产代码中编译出来。您仍然需要处理“永远不会发生”的控制路径以返回或抛出。即使 getScalarTypeWidth 可以返回的唯一可能值是 16、32 和 64,编译器也不知道。
  • @KillzoneKid:你们为什么要在 cmets 部分提供技术解释?请使用 cmets 请求澄清和批评问题。答案部分是技术响应的地方。
  • @Eljay:你也一样。

标签: c++


【解决方案1】:

assert 不算作控制流逻辑。这只是一个“记录”合同检查。在发布版本中它甚至不会发生!它只是一个调试工具。

因此,如果标量类型宽度不是 16、32 或 64,则剩下的函数会省略 return 语句。这意味着您的程序具有未定义的行为。警告告诉您,您需要在 所有 情况下返回某些内容,即使您认为其他情况不会在运行时发生。

在这种情况下,如果您通过switch 而不返回,我可能会抛出一个异常——这可能会像任何其他异常情况一样被处理。如果您不希望出现异常,另一种方法是自己调用std::terminate(这是断言最终将在调试版本中执行的操作)。

但是,终止是一种核选项,您真的不希望您的程序在生产中终止;您希望它通过您现有的异常处理渠道发出正确的诊断消息,以便当您的客户报告错误时,他们可以说“显然 makeFpConstant 得到了一个它没有预料到的值”并且您知道该怎么做。如果您不想将函数名称泄露给客户,那么您至少可以挑选一些只有您的团队/企业知道的“秘密”故障代码(并在内部记录下来!)。

不过,在调试版本中终止通常很好,所以也请留下 assert!或者只是依靠您现在拥有的异常,如果您没有捕获它,无论如何都会导致终止。

我可能会这样写函数:

Id Builder::makeFpConstant(
   const Id type,
   const double d,
   const bool specConstant
)
{
   assert(isFloatType(type));

   const auto width = getScalarTypeWidth(type);
   switch (width) {
      case 16: return makeFloat16Constant(d, specConstant);
      case 32: return makeFloatConstant(d, specConstant);
      case 64: return makeDoubleConstant(d, specConstant);
   }

   // Shouldn't get here!
   throw std::logic_error(
      "Unexpected scalar type width "
      + std::to_string(width)
      + " in Builder::makeFpConstant"
   );
}

【讨论】:

  • 在性能关键代码的紧密循环中,对std::terminate 的调用可能会更好。
【解决方案2】:

嗯,警告信息准确地说明了问题所在。

如果NDEBUG 已定义(即asserts 被禁用)并且cases 均未使用,则控件在任何return 语句之前到达函数末尾(这导致未定义行为)。

【讨论】:

  • 一种解决方案是插入一个调用来终止。
  • 但是如果-Wall也被启用,他的代码会产生警告。
  • @GRC 可能会。你想说什么?
  • 哦,实际上我想说的是,如果未定义NDEBUG,它将产生警告。我的评论更像是澄清而不是评论您的帖子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-06
  • 1970-01-01
  • 2013-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多