我做了一些研究,以找出为什么缺少的返回不能是错误,而是未定义的行为。我找到了 this comment in a bug report使用以下示例来说明为什么它不能是错误:
template<typename T> T maybe_call(std::function<T(void)> f) { if (f) return f(); else abort_program(); // Cannot write a return here, because we have no way to create a value of t }
请注意,此示例是完全有效的代码。它在所有分支上都没有返回,但仍然没有UB。这解释了为什么没有在所有分支上返回是 UB,而不是错误。该示例可以“固定”以声明
abort_program();
如 [[noreturn]]
让它不那么反驳。我怀疑编译器在正确诊断此示例时会遇到问题。如果错过返回会变成错误,规则可能需要稍微改变一下,因为只有 [[noreturn]]
上面的例子可以正确诊断。但是,我正在寻找的是一个不同的示例,其中编译器无法检测到丢失的返回。该评论还提到存在编译器无法诊断的案例,但我找不到这样的例子。
如果警告是可靠的(误报,如上面的那个除外),我可以将警告视为错误以安全起见。
是否真的存在编译器无法检测到丢失返回的情况?是仅在病态代码中,还是在日常代码中也会发生?我可以依赖警告吗?
为了使其易于回答,让我们专注于 gcc(最新版本):在什么情况下 gcc 无法警告丢失的返回?
最佳答案
很难证明某事不存在,但很难找到一个例子,足以令人信服地看到只有病态的代码才会导致编译器不警告丢失的返回。
首先,我的思路是构建一个复杂的例子:
int fun() {
goto exit;
return 1;
exit: ;
}
但是,无论我如何努力,gcc 都会警告此类代码。我想得越多,我就越相信问题不在于编译器不会警告的代码,而是假阳性。如果问题中的示例更改为
template<typename T>
T maybe_call(std::function<T(void)> f) {
if (f)
return f();
else
maybe_abort_program();
// Cannot write a return here, because we have no way to create a value of t
}
然后由编译器决定是否
maybe_abort_program
最终返回,这是无法在所有情况下决定的停机问题。更改函数的名称当然不会改变什么,但这只是为了强调即使认为函数可以 标记为 [[noreturn]]
, 不将其标记为这样代码仍然有效(或无效)并且编译器无法可靠地诊断它。但是,编译器可以警告此类情况。经过一番试验后,我没有找到任何编译器不警告的例子。因此我的结论是:我可以(在某种程度上)依赖警告。
关于c++ - 是否存在编译器无法诊断丢失返回的情况?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60966763/