How to compare pointers?

For a bit of facts here is the relevant text from the specifications

Equality operator (==,!=)

Pointers to objects of the same type can be compared for equality with the ‘intuitive’ expected results:

From § 5.10 of the C++11 standard:

Pointers of the same type
(after pointer conversions) can be compared for equality. Two pointers of the same type compare equal if
and only if they are both null, both point to the same function, or both represent the same address (3.9.2).

(leaving out details on comparison of pointers to member and or the null pointer constants – they continue down the same line of ‘Do What I Mean’:)

  • […] If both operands are null, they compare equal. Otherwise if only one is null, they compare unequal.[…]

The most ‘conspicuous’ caveat has to do with virtuals, and it does seem to be the logical thing to expect too:

  • […] if either is a pointer to a virtual member function, the result is unspecified. Otherwise they
    compare equal if and only if they would refer to the same member of the same most derived object (1.8)
    or the same subobject if they were dereferenced with a hypothetical object of the associated class type. […]

Relational operators (<,>,<=,>=)

From § 5.9 of the C++11 standard:

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

  1. 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.
  2. 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.
  3. 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.
  4. If two pointers point to non-static data members of the same object with
    different access control (Clause 11) the result is unspecified.
  5. 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.
  6. Other pointer comparisons are unspecified.

So, if you had:

int arr[3];
int *a = arr;
int *b = a + 1;
assert(a != b); // OK! well defined

Also OK:

struct X { int x,y; } s;
int *a = &s.x;
int *b = &s.y;
assert(b > a); // OK! well defined

But it depends on the something in your question:

int g; 
int main()
{
     int h;
     int i;

     int *a = &g;
     int *b = &h; // can't compare a <=> b
     int *c = &i; // can't compare b <=> c, or a <=> c etc.
     // but a==b, b!=c, a!=c etc. are supported just fine
}

Bonus: what else is there in the standard library?

§ 20.8.5/8: “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, you can globally order any odd void* as long as you use std::less<> and friends, not bare operator<.

Leave a Comment