Given that p is a pointer is “p > nullptr” well-formed?

后端 未结 1 1549
再見小時候
再見小時候 2021-02-18 16:18

Given a pointer p:

char *p ; // Could be any type

assuming p is properly initialized is the following well-formed:

1条回答
  •  攒了一身酷
    2021-02-18 16:38

    In C++14 this code is ill-formed but prior to the C++14 this was well-formed code(but the result is unspecified), as defect report 583: Relational pointer comparisons against the null pointer constant notes:

    In C, this is ill-formed (cf 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)?

    This has been in the language since the ARM (and possibly earlier); apparently it's because the pointer conversions (4.10 [conv.ptr]) need to be performed on both operands whenever one of the operands is of pointer type. So it looks like the "null-ptr-to-real-pointer-type" conversion is hitching a ride with the other pointer conversions.

    In C++14 this was made ill-formed when N3624 was applied to the draft C++14 standard, which is a revision of N3478. The proposed resolution to 583 notes:

    This issue is resolved by the resolution of issue 1512.

    and issue 1512 proposed resolution is N3478(N3624 is a revision of N3478):

    The proposed wording is found in document N3478.

    Changes to section 5.9 from C++11 to C++14

    Section 5.9 Relational operators changed a lot between the C++11 draft standard and the C++14 draft standard, the following highlights the most relevant differences (emphasis mine going forward), from paragraph 1:

    The operands shall have arithmetic, enumeration, or pointer type, or type std::nullptr_t.

    changes to:

    The operands shall have arithmetic, enumeration, or pointer type

    So the type std::nullptr_t is no longer a valid operand but that still leaves 0 which is a null pointer constant and therefore can be converted(section 4.10) to a pointer type.

    This is covered by paragraph 2 which in C++11 says:

    [...]Pointer conversions (4.10) and qualification conversions (4.4) are performed on pointer operands (or on a pointer operand and a null pointer constant, or on two null pointer constants, at least one of which is non-integral) to bring them to their composite pointer type. If one operand is a null pointer constant, the composite pointer type is std::nullptr_t if the other operand is also a null pointer constant or, if the other operand is a pointer, the type of the other operand.[...]

    this explicitly provides an exception for a null pointer constant operand, changes to the following in C++14:

    The usual arithmetic conversions are performed on operands of arithmetic or enumeration type. If both operands are pointers, pointer conversions (4.10) and qualification conversions (4.4) are performed to bring them to their composite pointer type (Clause 5). After conversions, the operands shall have the same type.

    In which there is no case that allows 0 to be converted to a pointer type. Both operands must be pointers in order for pointer conversions to be applied and it is required that the operands have the same type after conversions. Which is not satisfied in the case where one operand is a pointer type and the other is a null pointer constant 0.

    What if both operands are pointers but one is a null pointer value?

    R Sahu asks, is the following code well-formed?:

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

    Yes, in C++14 this code is well formed, both p and q are pointers but the result of the comparison is unspecified. The defined comparisons for two pointers is set out in paragraph 3 and says:

    Comparing pointers to objects is defined as follows:

    • If two pointers point to different elements of the same array, or to subobjects thereof, the pointer to the element with the higher subscript compares greater.

    • If one pointer points to an element of an array, or to a subobject thereof, and another pointer points one past the last element of the array, the latter pointer compares greater.

    • If two pointers point to different non-static data members of the same object, or to subobjects of such members, recursively, the pointer to the later declared member compares greater provided the two members have the same access control (Clause 11) and provided their class is not a union.

    Null pointers values are not defined here and later on in paragraph 4 it says:

    [...]Otherwise, the result of each of the operators is unspecified.

    In C++11 it specifically makes the results unspecified in paragraph 3:

    If two pointers p and q of the same type point to different objects that are not members of the same object or elements of the same array or to different functions, or if only one of them is null, the results of pq, p<=q, and p>=q are unspecified.

    0 讨论(0)
提交回复
热议问题