c++ - 编译器如何知道 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。
但我从评论中感觉到,这更多是一个非成熟实现的问题。
解决方案
您缺少的一点是常量表达式仅允许语言的受限子集。
如果您超出此范围,您将不再有一个常量表达式,并且如果您处于需要一个上下文的上下文中,则标准要求诊断错误。
一个constexpr
-function 只需有至少一个输入,它是一个常量表达式,不需要诊断。其余的可能都不是。
在一般情况下,编译器只记录通向 UB 的路径以修剪可能已死的代码,并探索他们在优化剩余代码方面的自由度。不过,他们不需要找到所有、大部分甚至任何这些机会。
推荐阅读
- python - 一年中给定月份的熊猫日期范围
- angular - 导入模块的顺序将注入的抽象覆盖到模块中
- flutter - RangeError(索引):无效值:有效值范围为空:Flutter中为0
- reactjs - 如何仅在 Ag-Grid 中导出当前页面中显示的数据?
- http - 如何在多部分请求中发送空白文件
- bash - 在 bash 中,为什么在这种情况下会忽略新行?
- c# - 如何在 FluentD 中使用转发插件时将输入读取为 json 并转发相同内容?
- distributed-database - 如何修改 TiDB 默认的 GLOBAL 变量,如 TiDB 中的“tidb_replica_read”值
- ansible - 该任务包括一个带有未定义变量的选项。错误是:“项目”未定义
- python - 如何向我的 python keras ANN 添加噪声(抖动)以避免过度拟合?