代码之家  ›  专栏  ›  技术社区  ›  W.F.

当短路禁用其求值时,是否允许在常量表达式中读取一个超过结束指针的值

  •  4
  • W.F.  · 技术社区  · 7 年前

    举个例子:

    template <char>
    struct foo { };
    
    int main() {
        foo<""[0]?""[1]:'\0'>{};
    }
    

    代码以两种方式编译 [gcc] [clang] ,但真的应该吗?我知道这个表达 ""[1] 由于短路,不需要进行评估。但标准并不十分清楚表达式是否可以真正限定为核心常量表达式。相关的 [expr.const]/2 尤其是部分:

    如果e满足核心常数表达式的约束,但是 e的计算将计算未定义的操作 本文件的[库]至[线程]中规定的行为, 未指定e是否为核心常量表达式。

    引起我的怀疑。。。

    2 回复  |  直到 7 年前
        1
  •  6
  •   paxdiablo    7 年前

    我相信摘录实际上涵盖了:

    如果 e 满足核心常量表达式的约束,但 e的评估将评估具有未定义行为的操作 如中所述 [library] 通过 [thread] 在本文件中,未明确是否 e 是一个核心常量表达式。

    实际上有 表达式中未定义的行为 ""[0]?""[1]:'\0' 因为唯一有问题的地方 ""[1] 永远不会 事实上 执行。事实上,整个表达式可以简单地优化为 '\0' 无不良反应。

    这个 原因 未执行来自标准本身(例如。, C++11 5.16 Conditional operator [expr.cond] /1 :

    条件表达式从右向左分组。第一个表达式在上下文中转换为 bool (第4条)。对其求值,如果为true,则条件表达式的结果为第二个表达式的值, 否则为第三个表达式。 只计算第二个和第三个表达式中的一个。

    自从 ""[0] 在布尔上下文中总是计算为false,第二个子表达式永远不会执行。它在概念上与表达式没有什么不同:

    false ? (1/0) : 42
    

    实际上,你永远不必担心被零除的可能性。

        2
  •  3
  •   StoryTeller - Unslander Monica    7 年前

    要回答这个问题,必须引用本段开头的话,其中说:

    表达式e是核心常数表达式,除非 e、 遵循抽象机器的规则,将评估 以下表达式:

    由于抽象机器的规则保证不会发生越界访问的评估( [expr.cond]/1 ):

    条件表达式从右向左分组。第一个表达式是 上下文转换为布尔。对其进行评估,如果为真,则 条件表达式的结果是第二个的值 表达式,否则为第三个表达式的表达式。 只有一个 计算第二个和第三个表达式 .

    没有未定义的行为,因此它必须是一个核心常量表达式。或者至少,不是你引用的子弹取消了它的资格。