Cole A
Cole A

Reputation: 65

How to recover offset in buffer of emplaced object from object pointer

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.

Upvotes: 4

Views: 109

Answers (1)

許恩嘉
許恩嘉

Reputation: 504

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.

Upvotes: 1

Related Questions