C++ Logo

std-proposals

Advanced search

Re: P1839 and the object representation of subobjects

From: Jason McKesson <jmckesson_at_[hidden]>
Date: Tue, 21 Jul 2020 11:01:13 -0400
On Tue, Jul 21, 2020 at 7:51 AM Giuseppe D'Angelo via Std-Proposals
<std-proposals_at_[hidden]> wrote:
>
> Hello,
>
> There's a long-ish thread [1] on the Qt mailing lists around using
> offsetof to obtain a pointer to a data member of a class (given a
> pointer to an object of that class), and vice versa, given a pointer to
> a data member, obtain a pointer to the enclosing object. Simplified:
>
> > class QObject { // non standard layout
> > QObjectPrivate *d_ptr;
> >
> > public:
> > virtual ~QObject();
> >
> > C1 c1; // possibly [[no_unique_address]]
> > C2 c2;
> > };
>
>
> And now, given
>
> > auto off = offsetof(QObject, c1); // OK, conditionally supported in 17
>
>
> Go from a pointer to QObject to a pointer to c1:
>
> > QObject *qoptr = ~~~;
> > auto c1ptr = reinterpret_cast<C1 *>(
> > reinterpret_cast<byte *>(qoptr) + off
> > );
> > assert(c1ptr == &qoptr->c1);
>
>
> and vice versa from c1 to the containing object:
>
> > auto qoptr2 = reinterpret_cast<QObject *>(
> > reinterpret_cast<byte *>(c1ptr) - off
> > );
> > assert(qoptr == qoptr2);
>
>
> Now, without P1839, the mere pointer arithmetic is already UB
> ([expr.add§6], as the paper explains) and one of the goals is fixing
> *that*. Something that the paper doesn't seem to do however is to give
> meaning to the above expressions: nowhere one is allowed to do the above
> casts (from within an object's representation to the actual object
> "stored there").
>
> Should it try and go that far? Was something like this ever proposed or
> discussed, maybe elsewhere? It would actually make offsetof *useful* (at
> the moment, the legal use cases sound rather limited).

We technically already have a way to do that: `std::launder`:

```
auto byte_ptr = reinterpret_cast<byte *>(qoptr);
auto c1ptr = std::launder(reinterpret_cast<C1 *>(qoptr + off);
```

If there is an object of type `C1` at the given address, then
`std::launder` will return a pointer to it. This is the purpose of
`launder`.

Received on 2020-07-21 10:04:35