【问题标题】:Given that p is a pointer is "p > nullptr" well-formed?鉴于 p 是一个指针,“p > nullptr”的格式是否正确?
【发布时间】:2014-12-22 18:59:30
【问题描述】:

给定一个指针p

char *p ; // Could be any type

假设 p 被正确初始化是以下格式:

if (p > 0) // or p > nullptr

更一般地说,当一个操作数是指针而另一个操作数是空指针常量时,使用关系运算符是否格式正确?

【问题讨论】:

    标签: c++ pointers c++11 language-lawyer c++14


    【解决方案1】:

    在 C++14 中,此代码格式错误,但在 C++14 之前,此代码格式正确(但结果未指定),如 defect report 583: Relational pointer comparisons against the null pointer constant 所述:

    在 C 中,这是格式错误的(参见 C99 6.5.8):

    void f(char* s) {
        if (s < 0) { }
    }
    

    ...但在 C++ 中,它不是。为什么?谁需要写 (s > 0) 他们什么时候可以写 (s != 0)?

    自 ARM 以来(可能更早),这一直是该语言; 显然是因为指针转换(4.10 [conv.ptr])需要 每当操作数之一为 指针类型。所以它看起来像“null-ptr-to-real-pointer-type” 转换与其他指针转换搭上了顺风车。

    在 C++14 中,当 N3624applied to the draft C++14 standardN3478 的修订版)时,它的格式不正确。建议的决议583 备注:

    此问题已通过问题 1512 的解决方案得到解决。

    问题1512建议的解决方案是N3478N3624 是 N3478 的修订版):

    建议的措辞可在文档 N3478 中找到。

    第 5.9 节从 C++11 到 C++14 的更改

    5.9 部分 关系运算符C++11 draft standardC++14 draft standard 之间发生了很大变化,以下突出显示了最相关的差异(强调我的未来) ,来自1段:

    操作数应具有算术、枚举或指针类型,或 键入 std::nullptr_t

    更改为:

    操作数应具有算术、枚举或指针类型

    所以std::nullptr_t 类型不再是有效的操作数,但仍然留下0,它是一个空指针常量,因此可以转换(4.10 部分 em>) 到一个指针类型

    这在 2 段中涵盖,在 C++11 中说:

    [...]指针转换 (4.10) 和限定转换 (4.4) 在指针操作数上执行(或在指针操作数和空 指针常量,或在两个空指针常量上,至少一个 这是非整数的)将它们带到它们的复合指针类型。 如果一个操作数是空指针常量,则复合指针类型 如果另一个操作数也是空指针常量,则为 std::nullptr_t 或者,如果另一个操作数是指针,则另一个的类型 操作数。[...]

    this 为 空指针常量 操作数显式提供异常,在 C++14 中更改为以下内容:

    通常的算术转换是在操作数上执行的 算术或枚举类型。 如果两个操作数都是指针,指针 执行转换 (4.10) 和资格转换 (4.4) 将它们带到它们的复合指针类型(第 5 条)。 之后 转换,操作数应具有相同的类型。

    在这种情况下,不允许将0 转换为指针类型。两个操作数都必须是指针才能应用指针转换,并且要求操作数在转换后具有相同的类型。这在一个操作数是 指针类型 而另一个是 空指针常量 0 的情况下不满足。

    如果两个操作数都是指针但一个是空指针值怎么办?

    R Sahu 提问,下面的代码格式正确吗?:

    char* p = "";
    char* q = nullptr;
    if ( p > q ) {}
    

    是的,在 C++14 中,这段代码格式正确,pq 都是指针,但比较的结果是未指定的。两个指针的定义比较在段落3 中列出,并说:

    比较指向对象的指针定义如下:

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

    • 如果一个指针指向数组的一个元素或其子对象,而另一个指针指向数组的最后一个元素之后 数组,后一个指针比较大。

    • 如果两个指针以递归方式指向同一对象的不同非静态数据成员或此类成员的子对象,则 指向后面声明的成员的指针比较更大,前提是两者 成员具有相同的访问控制(第 11 条)并提供他们的 类不是联合。

    此处未定义空指针值,稍后在4 段中写道:

    [...]否则,每个运算符的结果都是未指定的。

    在 C++11 中,它专门使 3 段中未指定结果:

    如果两个相同类型的指针p和q指向不同的对象 不是同一对象的成员或同一数组的元素 或者不同的函数,或者如果其中只有一个为空,则结果 pq、p=q 的数量未指定。

    【讨论】:

    • 这是否意味着char* p = ""; char* q = nullptr; if ( p &gt; q ) {} 还可以?
    • @RSahu 我对34 的阅读,我没有从标准草案N3936 中引用,是该比较的结果是未指定的,但自pq 都是指针。
    • 第 3 段很奇怪。实际上,如果一个实现必须使比较工作,如果两者都不为空,并且如果它们是同一对象的成员或同一数组的元素,那么使结果 满足,则>not是可预测的和合乎逻辑的。对我来说,这是一组非常令人困惑和超特定的约束。 (尽管我想,在例外中添加例外到规则例外和创可贴到创可贴到创可贴,这当然是 C++ 的传统。)
    • @JasonC 确实非常具体,我认为这是为了确保仅在不改变概念的情况下明显有意义的情况下进行明确定义的排序。
    • @JasonC 在 C++ 中查看指针比较/等的方法是考虑一个严重分段的内存模型。指针分为高位和低位字组件,其中高位字是段。这些部分重叠。给定的 C++ 结构必须适合给定的段(实际上它通常不允许到达末尾),这允许仅与低字数据发生许多指针比较,通常会提高性能。 null 可能是 0 段 0 偏移指针,也可能是 -1 段 -1 偏移指针,因为 0 0 用于硬件中的某些东西!
    猜你喜欢
    • 2011-10-19
    • 1970-01-01
    • 2012-07-26
    • 2019-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-04
    • 1970-01-01
    相关资源
    最近更新 更多