代码之家  ›  专栏  ›  技术社区  ›  463035818_is_not_an_ai

“不需要”==未定义的行为?

  •  4
  • 463035818_is_not_an_ai  · 技术社区  · 5 年前

    我的问题主要是关于术语和如何解释标准。

    [expr.rel]#4 :

    将不等指针与对象进行比较的结果根据与以下规则一致的偏序来定义:

    (4.1)如果两个指针指向同一数组的不同元素, 指向具有较高值的元素的指针 下标是比较大值所必需的。

    (4.2)如果两个指针指向 同一对象的不同非静态数据成员,或 这些成员的子对象,递归地,指向后者的指针 声明的成员需要比较两者中的较大值 成员具有相同的访问控制([class.access]),两个成员都没有 是一个大小为零的子对象,它们的类不是联合体。

    (4.3)否则,两个指针都不需要比较大于 其他。

    对于如何解读(4.3),我并不感到困惑。这是否意味着

    #include <iostream>
    int main() {
        int x;
        int y;
        std::cout << (&x < &y);
        std::cout << (&x < &y);
    }
    

    是。。。

    • 有效的C++代码,输出为 11 00 .
    • 无效代码,因为它具有未定义的行为

    ?

    换句话说,我知道(4.3)确实适用于这里,但我不确定其含义。当标准说“它可以是A或B”时,这与说“它没有定义”是一样的吗?

    3 回复  |  直到 5 年前
        1
  •  26
  •   Keith Thompson    5 年前

    C++标准的各个版本以及问题中引用的最新草案中的措辞都发生了变化。(有关血腥的细节,请参阅我对这个问题的评论。)

    C++11说:

    其他指针比较未指定。

    C++17说:

    否则,两个指针的比较值都不会大于另一个指针。

    问题中引用的最新草案说:

    否则,两个指针都不需要比另一个指针更大。

    这一变化是为了回应 issue 说“比较大”这个词是不必要的混淆。

    如果你看看标准草案中的周围环境,很明显,在其余情况下,结果是 未指定 引用[expr.rel](斜体文本是我的总结):

    将不等指针与对象进行比较的结果在中定义 符合以下规则的偏序条款:

    • [指向同一数组元素的指针]

    • [指向同一对象成员的指针]

    • [其余案件] 否则,两个指针都不需要比另一个指针更大。

    如果两个操作数 p q 比较相等, p<=q p>=q 两者产量 true p<q p>q 两者产量 false 。否则,如果指针 p 比指针大 q, p>=q, p>q, q<=p, q<p 全部的 产量 真的 p<=q , p<q , q>=p ,以及 q>p 全部收益 错误的 否则,每个运算符的结果 未指定。

    因此,结果 < 在这种情况下,运算符是未指定的,但它没有未定义的行为。它可以是真的或假的,但我不认为它必须是一致的。程序的输出可以是以下任何一种 00 , 01 , 10 ,或 11 .

        2
  •  7
  •   cigien Jorge Eldis    5 年前

    对于提供的代码,此情况适用:

    (4.3)否则,两个指针都不需要比另一个指针更大。

    没有提到UB,因此严格阅读“两者都不需要”表明,每次评估比较的结果都可能不同。

    这意味着程序可以有效地输出以下任何结果:

    00
    01
    10
    11
    
        3
  •  4
  •   463035818_is_not_an_ai    5 年前

    有效的C++代码

    对。

    标准中没有任何地方说这是UB或格式不正确的,而且这种情况也不缺乏描述行为的规则,因为引用的4.3适用。

    输出为11或00

    我不确定10或01在技术上是否保证不会输出 1. .

    鉴于此 两个指针都不需要比另一个指针更大 ,比较结果可以是true或false。在这种情况下,似乎没有明确要求对相同操作数的每次调用的结果都是相同的。

    1. 但我认为这在实践中不太可能。我也认为,让这种可能性保持开放并不是故意的。相反,其目的是允许确定性,但不一定是全序。


    附笔。

    auto comp = std::less<>;
    
    std::cout << comp(&x, &y);
    std::cout << comp(&x, &y);
    

    将保证为11或00,因为 std::less (像它的朋友一样)保证对指针施加严格的总顺序。

        4
  •  2
  •   Remy Lebeau    5 年前

    x y 根据(4.1),它们不属于同一数组。根据(4.2),它们不是同一对象的成员。因此,你陷入了(4.3),这意味着如果你试图将它们相互比较,比较的结果是 不确定 能够 要真实 错误的如果是 未定义行为 相反,该标准可能会明确指出这一点。