Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

Does the assertion in the following code snippet always hold?

std::less<Object *> lessPtr;
Object * o = new Object();
assert(lessPtr (o, nullptr) == false);
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
264 views
Welcome To Ask or Share your Answers For Others

1 Answer

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share

548k questions

547k answers

4 comments

86.3k users

...