In writing a custom allocator, I have a situation like the MWE below where placement-new is used to construct an object of type S at a suitably aligned position in a buffer, yielding a pointer of type "pointer to S", which is handed out. This pointer is returned to me later, at which time I want to determine the offset of the first byte of the pointed-to object from the start of the buffer (24 in this example). My question is whether line (b) below is well-defined and if not, what the correct (UB-free) way is to compute this offset. (gcc with -fsanitize=undefined emits no diagnostic.)
#include <cstddef>
#include <cstdio>
#include <new>
struct alignas(8) S { int x; };
int main()
{
alignas(8) std::byte buf[80];
S* const sp{new (buf + 24) S{42}};
// ...
std::byte* const bp{reinterpret_cast<std::byte*>(sp)}; // (a)
const ptrdiff_t off{bp - buf}; // (b)
printf("%td\n", off);
}
My understanding is that after array-to-pointer decay, the expression buf is a pointer of type "pointer to std::byte" that points to the 0-th element of the array of element type std::byte. It seems what [expr.add]p5 requires for line (b) to be well-defined is that bp also be a pointer of type "pointer to std::byte" that points to an element (or one past the end) of the same array. bp should have the requisite type due to the reinterpret_cast on line (a), but since S and std::byte are not pointer-interconvertible, the value of bp is unchanged by the cast so would still be "pointer to *sp", i.e. bp aliases (points to) the object of type S nested in the array. It is unclear to me whether bp pointing to the object of type S nested in the array means bp points to an element of the array itself as well or not, for the purpose of applying [expr.add]p5.
The correct way to compare distances between pointers to different objects is to convert them to integers.
The pointer-to-integer conversion is implementation-defined, which means that your implementation must document how it works. If your implementation defines the pointer-to-integer conversion as producing the numeric value of the linear address of the object referenced by the pointer, and you know that you are on a flat architecture, then what you can do is compare integers rather than pointers. Integer comparisons are not constrained in the same way that pointer comparisons are.
Raymond Chen's blog has a lot of C++ and Win32 knowledge. Although you won’t find the answers to all your questions on his blog, if you can find the answer there, it will definitely be an easy-to-understand answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With