代码之家  ›  专栏  ›  技术社区  ›  Matteo Italia

为什么C++ 11包含一个比较空洞指针的奇数子句?

  •  57
  • Matteo Italia  · 技术社区  · 6 年前

    在检查另一个问题的引用时,我注意到C++ 11中的一个奇怪的子句,[ExpR.Re] 3。

    指针指向 void (指针转换之后)可以与定义如下的结果进行比较:如果两者都是 指针表示相同的地址或都是空指针值,结果是 true 如果操作员是 <= >= false 否则,结果未指定。

    这似乎意味着,一旦两个指针被投到 void * ,它们的排序关系不再得到保证;例如:

    int foo[] = {1, 2, 3, 4, 5};
    void *a = &foo[0];
    void *b = &foo[1];
    std::cout<<(a < b);
    

    似乎没有具体说明。

    有趣的是,这个子句不存在于C++ 03中,在C++ 14中消失了,因此,如果我们举上面的例子并将C++ 14的措辞应用到它中,我会说“3.1”。

    • 如果两个指针指向同一数组的不同元素或其子对象,则下标较高的元素的指针会比较大。

    将适用于 a b 指向同一数组的元素,即使它们被强制转换为 空洞* .注意,在C++ 11中,第3.1条的措辞几乎是相同的,但似乎被 空洞* 条款。

    我的理解正确吗?在C++ 11中添加的OdDoul子句是什么意思,并立即删除?或者它仍然在那里,但是被转移到/被标准的其他部分所暗示?

    1 回复  |  直到 6 年前
        1
  •  35
  •   Matteo Italia    6 年前

    DR:

    • 在C++ 98/03中,该子句不存在,并且标准没有指定关系运算符。 void 指针(核心问题879,见本帖末尾);
    • 关于比较的奇怪条款 无效 指针被添加到C++ 11中来解决它,但是这又引起了583和1512的两个其他核心问题(见下文);
    • 这些问题的解决需要删除子句,并用C++ 14标准中的措词来代替,这允许“正常”。 void * 比较。

    核心问题583: Relational pointer comparisons against the null pointer constant

    1. 与空指针常量部分的关系指针比较:8.9[expr.rel]

    在c中,这是不正确的(参见c99 6.5.8):

    void f(char* s) {
        if (s < 0) { }
    } ...but in C++, it's not. Why? Who would ever need to write (s > 0) when they could just as well write (s != 0)?
    

    这是ARM以来的语言(可能更早); 显然,这是因为指针转换(7.11[conv.ptr])需要 在两个操作数上执行,只要其中一个操作数是 指针类型。所以它看起来像“空指针到实际指针类型” 转换是把一辆车挂在另一个指针转换上。

    拟议决议(2013年4月):

    这个问题是通过解决 问题1512 .

    核心问题1512: Pointer comparison vs qualification conversions

    1. 指针比较与限定转换部分:8.9[expr.rel]

    根据8.9[expr.rel]第2段,描述指针 比较,

    指针转换(7.11[conv.ptr])和限定转换 (7.5[conv.qual])在指针操作数(或指针)上执行。 操作数和一个空指针常量,或在两个空指针常量上, 其中至少有一个是不可积的)使它们 复合指针类型。这似乎使 示例格式错误,

     bool foo(int** x, const int** y) {
     return x < y;  // valid ?   } because int** cannot be converted to const int**, according to the rules of 7.5 [conv.qual] paragraph 4.
    

    对于指针比较来说,这似乎太严格了,当前 实现接受示例。

    拟议决议(2012年11月):


    相关摘录 上述问题的解决 在论文中发现: Pointer comparison vs qualification conversions (revision 3) .

    下面还解析了核心 问题583 .

    5.9 expr.rel第1至5段中的变更:

    在本节中,以下陈述 C++ 11中的奇数子句 已经 删去 :

    指针指向 无效 (指针转换之后)可以与如下定义的结果进行比较:如果两个指针表示相同的地址或都是空指针值,则结果为 true 如果操作员是 <= >= false 否则,结果未指明

    以下陈述 补充 :

    • 如果两个指针指向同一数组的不同元素或其子对象,则下标较高的元素的指针会比较大。
    • 如果一个指针指向数组的一个元素或其子对象,而另一个指针指向数组的最后一个元素的一个以上,则后者的指针比较大。

    所以在最后的工作草案 C++ 14 (n4140)第[expr.rel]/3节,上述声明与决议时所述内容一致。


    挖掘这个奇怪的条款被添加的原因,我得出了一个更早的问题879: Missing built-in comparison operators for pointer types . 该问题的拟议解决方案(2009年7月)增加了该条款,该条款于2009年10月投票给了WP。

    这就是它被包含在C++ 11标准中的原因。