Does the assertion in the following code snippet always hold?
std::less
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.
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
andq
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, thenp<=q
andp>=q
both yieldtrue
andp<q
andp>q
both yieldfalse
.If two pointers
p
andq
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 ofp<q
,p>q
,p<=q
, andp>=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
, andless_equal
, the specializations for any pointer type yield a total order, even if the built-in operators<
,>
,<=
,>=
do not.
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.