Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using std::less with nullptr

Tags:

c++

c++11

Does the assertion in the following code snippet always hold?

std::less<Object *> lessPtr;
Object * o = new Object();
assert(lessPtr (o, nullptr) == false);
like image 660
Alexander Avatar asked Mar 02 '15 13:03

Alexander


People also ask

Can you compare to nullptr?

No, you cannot have ordered comparisons of nullptr or other null pointer constants with pointers.

Is nullptr better than null?

As a reminder, since C++11, NULL can be either an integer literal with value zero, or a prvalue of type std::nullptr_t . Because of this ambiguity, I recommend switching exclusively to nullptr . nullptr will make your code less error-prone than relying on the implementation-defined NULL .

Should we set pointers to nullptr?

It is always a good practice to assign the pointer NULL to a pointer variable in case you do not have exact address to be assigned. This is done at the time of variable declaration. A pointer that is assigned NULL is called a null pointer.

Is nullptr same as null C++?

Nullptr vs NULLNULL is 0 (zero) i.e. integer constant zero with C-style typecast to void* , while nullptr is prvalue of type nullptr_t , which is an integer literal that evaluates to zero.


1 Answers

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
like image 189
Filip Roséen - refp Avatar answered Sep 29 '22 09:09

Filip Roséen - refp