简体   繁体   中英

Using std::less with nullptr

Does the assertion in the following code snippet always hold?

std::less<Object *> lessPtr;
Object * o = new Object();
assert(lessPtr (o, nullptr) == false);

Introduction

This question really boils down to whether the use of the less-than relational operator on pointer types where one operand is a nullptr will yield the "expected" result; which sadly isn't the case.

The result is unspecified .

Note: Do mind that std::less guarantees a total order ; meaning that even if the result, when using the function object, is unspecified , it must yield the same unspecified value on each invocation.


What does the International Standard ( N3337 ) say?

5.9p2 Relational operators [expr.rel]

Pointers to objects or functions of the same type (after pointer conversions) can be compared, with a result defined as follows:

  • If two pointers p and q of the same type point to the same object or function, or both point one past the end of the same array, or are both null, then p<=q and p>=q both yield true and p<q and p>q both yield false .

  • 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 p<q , p>q , p<=q , and p>=q are unspecified.

  • If two pointers point to non-static data members of the same object, or to subobjects or array elements 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.

  • If two pointers point to non-static data members of the same object with different access control (Clause 11) the result is unspecified.

  • If two pointers point to non-static data members of the same union object, they compare equal (after conversion to void* , if necessary). If two pointers point to elements of the same array or one beyond the end of the array, the pointer to the object with the higher subscript compares higher.

  • Other pointer comparisons are unspecified.

20.8.5p8 Comparison [comparision]

For templates greater , less , greater_equal , and less_equal , the specializations for any pointer type yield a total order, even if the built-in operators < , > , <= , >= do not.


So, what is the standard really saying?

T * p = new T;
T * q = nullptr;


What is the verdict for p < q ?
Since p and q don't point to different elements of the same array (including the element one past the last element of an array), and both don't point to non-static data members of the same object; the result when doing p < q (and p > q ) is unspecified .

bool a = p < q;  // unspecified
bool b = p < q;  // unspecified

assert (a == b); // can fire


What about std::less ?
However, when using std::less we are guaranteed a total order - which effectively means that the below assertion cannot fire ( standard-20.8.5p8 ).

std::less<T*> comp;

bool a = comp (p, q);  // unspecified
bool b = comp (p, q);  // unspecified

assert (a == b);       // can not fire

No, the ordering of a null pointer relative to any non-null pointer is unspecified.

The result of the comparision operators is unspecified if the operands "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".

std::less and friends extend this to specify that there's a total order, but don't specify where null pointers occur in that order. So it's guaranteed that null will consistently be either greater than, or less than, any given non-null pointer. But it's not specified to be either less than, or greater than, all non-null pointers.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM