Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Universal less<> for pointers in C++ standard

Tags:

c++

People also ask

What type is std :: less?

The std::less is a is a member of the functional class (<functional. h>) used for performing comparisons. It is defined as a function object class for less than inequality comparison which returns a boolean value depending upon the condition.

Can map keys be pointers?

C++ standard provided specialisation of std::less for pointers, so yes you can safely use them as map keys etc.

Can you compare pointers of different types?

When two pointers are compared, the result depends on the relative locations in the address space of the objects pointed to. If two pointers to object types both point to the same object, or both point one past the last element of the same array object, they compare equal.


Two pointers can be compared with using the comparison function objects less, greater etc. Otherwise, using blanket operator< etc, this is only possible if the pointers point to elements of the same array object or one past the end. Otherwise, results are unspecified.

20.3.3/8 in C++03

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.

No need to explicitly specialize and manually casting to size_t: That would lower the portability even, since the mapping of reinterpret_cast from pointers to integers is implementation defined and is not required to yield any order.


Edit: For a more detailed answer, see this one.


No, it's not available. The standard says that pointers are only comparable with the built-in operators when they point to the same array or other memory block. That is, the block needs to have been allocated all at once, as opposed to two separate allocations that might happen to be adjacent to each other.

This is OK:

int x[2];
bool b = &x[0] < &x[1];

This is undefined:

int x0;
int x1;
bool b = &x0 < &x1;

This is OK:

struct foo {
  int x0;
  int x1;
};
foo f;
bool b = &f.x0 < &f.x1;

Both values are members of the same struct, so they belong to the same block of memory (namely, f's).

Practically speaking, though, there's nothing wrong with your custom-defined comparison.

However, your custom specialization is unnecessary, since the std::less template is defined for pointers, evidently. So this is OK:

int x0;
int x1;
std::less<int*> compare;
bool b = compare(&x0, &x1);

There's still no indication of what the result must be, but you're at least promised to have some result, as opposed to undefined behavior. You get a total order, but you don't know what order until you run it.


Comparing pointers is a pretty fraught business. It only makes sense to compare pointers if they both point into the same block of memory, otherwise the operation is undefined. A (valid) set of pointers is therefore a pretty specialised thing, and no, the Standard Library doesn't have one.


Even though you may think that comparing the bits of pointers is harmless (after all, they're just addresses in memory, right?), there are good reasons why the language standard doesn't encourage it. For one, if you have code whose results depend on the relative ordering of pointers (e.g, the order of results depends on iteration order through a set or map of pointers), the results will be unstable: Changing the version of compiler or operating system release can change the results. Reproducibility is valuable enough to make this instability worth avoiding.


Comparing pointers that are not allocated in the same block is undefined, probably because there are memory models that have problems with them (and used to be more common).

What you need to use is unordered_set<>, which doesn't appear to require a comparison operator. It's in the next C++ standard, and available as a Boost header in the meantime.