C++ Logo

std-discussion

Advanced search

Re: Pointer comparison with operators vs function objects

From: Andrey Semashev <andrey.semashev_at_[hidden]>
Date: Tue, 16 Sep 2025 13:33:44 +0300
On 15 Sep 2025 16:48, David Brown via Std-Discussion wrote:
>
> First ask yourself, is there any reason why you would want to compare
> unrelated pointers for ordering?

One common use case is testing whether the pointers point to a subobject
of the same object. For example, if a pointer points within a string or
an array. This check is often needed to properly implement operations on
the string/array, such as selecting the direction of element iteration.

> Such comparisons can be helpful for implementations of standard
> functions like memmove(). But those are part of the implementation - a
> standard library implementation can use compiler-specific features or
> implementation-specific knowledge to implement its functions
> efficiently, relying on features that are not part of the C++ standards.

Memmove is not always applicable, e.g. when the elements are not
trivially copyable. And testing as part of the copy operation may not be
enough. Consider e.g. a call to std::string::insert, where the inserted
string may part of the target string. You would have to test whether the
inserted string is part of the target string before you perform the copy
because that will affect how you perform the copy.

> There might be occasions when user-written code can have an interest in
> orderings of pointers, such as for writing specialised memory management
> routines or perhaps holding unrelated pointers in a searchable data
> structure. I would expect that for those situations, you can simple
> cast to uintptr_t and compare those without any overhead. (Use the
> casts just for the comparisons - avoid casting back and forth between
> uintptr_t and pointer types because the compiler might lose useful
> information.) You will probably find that this is what is being the
> std::less implementation in many C++ libraries.

This misses the rationale why the casts are needed in the first place.

> As for why comparing unrelated pointers (except for equality) is UB,
> this might be because C and C++ can work on systems with complicated
> address spaces. Modern x86, ARM, and other common "big" processors have
> nice, simple flat address spaces. But some other targets have
> complicated address spaces - the same underlying representation in a
> pointer might refer to different physical addresses depending on its
> type or how the pointer is used. (An example of a currently available
> processor with multiple address spaces and with C++ support is the AVR
> microcontroller family.)

And on such systems casts to uintptr_t would make the comparisons
invalid, right?

> On many such systems, it would be possible to
> define a comparison relationship - but why bother, if the results don't
> actually mean anything?

The meaning would be the same as std::less. Specifically, the unrelated
pointers are unordered (meaning, unrelated pointers compare
consistently, but possibly differently on every run of the program) and
pointers within the object compare as if the pointers were offsets from
the beginning of the object representation.

Really, the language already defines the logic under the name of
std::less. Why the same logic cannot be invoked as the built-in
operrator< for pointers?

Received on 2025-09-16 10:33:49