首页 > 解决方案 > 编译器如何知道 C++ constexpr 计算不会触发未定义的行为?

问题描述

C++ 标准要求编译器检查C++ constexpr 计算中的未定义行为

本次演讲中,Chandler Carruth 表示,在检查 UB 时“您将失去检测错误的能力”,并且在一般情况下,检测 UB 与停机问题有关,因此无法确定

他不是在谈论 constexpr 中的 UB,但constexpr 计算与自 C++14 以来的常规程序一样通用,所以这仍然适用。

那么当编译器无法确定一个程序是否是 UB 时,他们会怎么做呢?他们是否仍然接受程序并继续编译?还是他们更保守并拒绝该计划,即使它可能是正确的?(我个人的感觉是他们这样做)

对我来说,这具有实际意义,因为我有一个 constexpr 评估,其中非平凡的指针算术用 Clang 编译得很好,但用 GCC 失败了,我很确定这不是 UB。你可以说它是一个 GCC 错误,但如果 UB 是不可判定的,那么所有编译器在这方面都是并且将会是错误的。

更根本的是,为什么标准要求 UB-free?有技术原因吗?或者更多的是哲学上的(“如果编译器无法检查,程序员可以触发UB,就会导致坏事”)?

我认为这与 C++ 的其余部分不一致,它永远不会阻止你在脚下开枪。我希望 GCC 接受我的 constexpr 代码并崩溃,或者如果 UB 则发出垃圾;而不是在不知道是不是UB的时候不编译。

====== 编辑======

正如 MM 和 Nicol Bolas 所指出的,该标准指定了限制(即使在 C++14 中),因此我们永远不会遇到 UB 的停止问题类型。但是,我仍然想知道检查 UB 是否可能过于复杂,并且如果编译器启发式失败,那么他们将其(可能不正确)标记为非 constexpr。

但我从评论中感觉到,这更多是一个非成熟实现的问题。

标签: c++language-lawyerundefined-behaviorconstexpr

解决方案


您缺少的一点是常量表达式仅允许语言的受限子集。

如果您超出此范围,您将不再有一个常量表达式,并且如果您处于需要一个上下文的上下文中,则标准要求诊断错误。

一个constexpr-function 只需有至少一个输入,它是一个常量表达式,不需要诊断。其余的可能都不是。

在一般情况下,编译器只记录通向​​ UB 的路径以修剪可能已死的代码,并探索他们在优化剩余代码方面的自由度。不过,他们不需要找到所有、大部分甚至任何这些机会。


推荐阅读