此函数是不是在所有控制路径上都有明确的返回值?

Posted

技术标签:

【中文标题】此函数是不是在所有控制路径上都有明确的返回值?【英文标题】:Does this function have explicit return values on all control paths?此函数是否在所有控制路径上都有明确的返回值? 【发布时间】:2018-03-10 02:16:24 【问题描述】:

我有一个Heaviside step function,它以任何数据类型的统一为中心,我使用以下代码对其进行了编码:

template <typename T>
int h1(const T& t)
   if (t < 1)
       return 0;
    else if (t >= 1)
       return 1;
   

在代码审查中,我的审查者告诉我,并非所有控制路径都明确返回。编译器也没有警告我。但我不同意;条件是互斥的。我该如何处理?

【问题讨论】:

return t &gt;= 1; 在没有分支的情况下给你同样的... 出于兴趣,为什么这个函数需要模板化?您是否真的将它用于不同的类型? @KobyDuck 不能保证return a+b; 不会分支,或者return 1; 不会分支。 C++ 对“将代码分支”做出零保证。您可以消除抽象机中的分支,并且可以使用编译器已知的习语在可用时发出无分支指令。 考虑在特殊情况下抛出domain_error 你有这么关心的评论者吗?数一数你的祝福! 【参考方案1】:

这取决于模板的使用方式。对于int,你很好。

但是,如果t是IEEE754浮点型double,其值设置为NaN,则t &lt; 1t &gt;= 1都不是true,所以程序控制到达if 块的末尾!这会导致函数在没有显式值的情况下返回;其行为未定义。

(在更一般的情况下,T 重载 &lt;&gt;= 运算符以不涵盖所有可能性,程序控制将到达 if 块的末尾而没有显式return.)

这里故事的寓意是决定哪个分支应该是默认的,并将那个分支设为else 的情况。

【讨论】:

【参考方案2】:

仅仅因为代码是正确的,并不意味着它不可能更好。正确执行是质量的第一步,而不是最后一步。

if (t < 1) 
    return 0;
 else if (t >= 1)
    return 1;

以上对于t 的任何数据类型都是“正确的”,而不是&lt;&gt;= 的正常行为。但是这个:

if (t < 1) 
    return 0;

return 1;

通过检查更容易看出每种情况都已涵盖,并且完全避免了第二次不必要的比较(某些编译器可能没有优化)。代码不仅可以被编译器读取,还可以被人类读取,包括 10 年后的你。让人类休息一下,写得更简单,以供他们理解。

【讨论】:

我知道你想说什么(有一个赞成票),但这里暗示 IEEE754 类型不是“理智的”。这是你的意思吗?我也很想看到一个编译器优化第二个条件检查的例子。 @Bathsheba:我不认为说NaN 不是“理智的”是完全不合理的- numeric 类型的值不是 number,因此类型没有排序?显然我知道它为什么存在:争论不是float 应该 做这样的事情,而只是它导致了无意义的排序操作。我想有人可以说这样表达是不合理的,因为社会普遍使用精神疾病作为任何困难或意外的类比的内在能力。 @Bathsheba 我认为partially ordered set 理智(它允许x&lt;1x&gt;=1 都是错误的),但我认为IEEE 浮动是疯狂的,因为== 不是等价关系并且比较不'不符合部分排序的要求。 @Bathsheba,gcc -O2(和 -O3)删除了与整数 t 的第二次比较。【参考方案3】:

如前所述,一些特殊的数字可以是&lt;&gt;=,所以你的审阅者是对的。

问题是:最初是什么让您想这样编写代码?为什么你甚至考虑让自己和他人(需要维护你的代码的人)的生活变得如此艰难?仅仅你足够聪明地推断出&lt;&gt;= 应该涵盖所有情况并不意味着你必须使代码变得比必要的更复杂。物理学也适用于代码:让事情尽可能简单,但不是更简单(我相信爱因斯坦是这么说的)。

考虑一下。你想达到什么目的?必须是这样的:'如果输入小于 1,则返回 0,否则返回 1。您所做的是通过说...增加智能...哦,但这意味着如果 t 大于或等于 1,我将返回 1。这种不必要的“x 意味着 y”需要代表维护者进行额外的思考工作。如果您认为这是一件好事,我建议您自己进行几年的代码维护。

如果这是我的评论,我会再发表评论。如果你使用“if”语句,那么你基本上可以在所有分支中做任何你想做的事情。但在这种情况下,你什么都不做。您要做的就是根据 tif 语句好多 更好、更易读。因此:

return t&lt;1 ? 0 : 1;

我知道?: 运算符在某些公司中是被禁止的,我觉得这样做很糟糕。 ?: 通常与规范匹配得更好,它可以使代码更容易阅读(如果小心使用的话)...

【讨论】:

我更喜欢 return !(t &lt; 1);return t &gt;= 1; 取决于哪一个是“包罗万象”的案例。 @Bathsheba 虽然您在技术上是正确的,但由于 true==1 和 false==0,Bert 的解决方案仍然更忠实于 OP 的原件,无论如何这可能是真实代码的简化案例. @Bathseba 原始问题显示int 返回。您依赖隐式转换,但我喜欢能够准确显示我们意图的代码。如果意图是返回一个布尔值,那么返回值应该是一个布尔值。其次,从该代码中,我推断出其意图是在“catch-all”分支上返回1(当然事实并非如此)。因此,无需像 return !(t &lt; 1) 那样混淆事物。

以上是关于此函数是不是在所有控制路径上都有明确的返回值?的主要内容,如果未能解决你的问题,请参考以下文章

方法错误“并非所有控制路径都返回值”和方法未返回值[关闭]

返回值中的函数混淆,啥是明确的真假?

如何检查所有代码路径是不是返回值

python的线程如何返回值?

从递归函数expressjs返回空数组?

Windows GetLastError()返回值