C++ Logo

std-discussion

Advanced search

Re: Is it valid use reinterpret_cast to form pointer to object?

From: Mykola Garkusha <garkusha.mykola_at_[hidden]>
Date: Sun, 6 Aug 2023 18:20:00 +0100
Thanks, this is super clear actually. Everything settled after deep diving
into pointer conversions for non-pointer-interconvertible objects.

So then with std::launder, this shall work as it should return pointer
value "pointer to T"?

T2* ptr2 = std::laudner(reinterpret_cast<T2 *>(&storage_))
ptr2->value...


On Sun, Aug 6, 2023 at 5:39 PM Matthew House via Std-Discussion <
std-discussion_at_[hidden]> wrote:

> On Sun, Aug 6, 2023 at 10:03 AM Mykola Garkusha
> <garkusha.mykola_at_[hidden]> wrote:
> > Just want to clarify this clearly to be 100% sure.
> >
> > > Not in general; [basic.lval] para. 11 is specifically about reading
> > > and writing scalar values through a glvalue, and nothing else. Since
> > > ptr2 is a T* pointer pointing to an std::byte object, you can't do
> > > most things with ptr2 that you could do with an arbitrary T* pointer,
> >
> > ptr2 should point to T2 now
> >
> > https://eel.is/c++draft/expr#reinterpret.cast-7
> > https://eel.is/c++draft/expr#reinterpret.cast-3
>
> That's not how it works in this case, since the two objects 'storage_'
> and '*ptr_' are not pointer-interconvertible. By
> [expr.reinterpret.cast] para. 7, 'T* ptr2 =
> reinterpret_cast<T*>(&storage_)' is equivalent to 'T* ptr2 =
> static_cast<T*>(static_cast<void*>(&storage_))'. Here, '&storage_'
> points to the entire 'storage_' array (not to its first element
> 'storage_[0]', as I mistakenly said earlier), so by [expr.static.cast]
> para. 4 and [conv.ptr] para. 2, 'static_cast<void*>(&storage_)' also
> points to the 'storage_' array.
>
> For 'T* ptr2 = static_cast<T*>(...)', we have to look at
> [expr.static.cast] para. 14: *if* there exists an object of type
> (similar to) T pointer-interconvertible with 'storage_', then 'ptr2'
> will point to that T object; *otherwise*, 'ptr2' will be a T* pointer
> pointing to the 'storage_' array. But if we look at the definition of
> pointer-interconvertible objects in [basic.compound] para. 4, none of
> those bullets apply for 'storage_' and '*ptr_': they are different
> objects, neither is a union object, and neither is the first
> non-static member of the other. Therefore, 'ptr2' is a T* pointer
> pointing to the std::byte[sizeof(T)] array 'storage_', not a T*
> pointer pointing to the T object '*ptr_'.
>
> > Not sure how strict aliasing (https://eel.is/c++draft/expr#basic.lval-11)
> can be violated in the example below, as the access (for scalar variables)
> would be done through dynamic type, as T2 lifetime has started and storage_
> provides storage for it.
> > T2* ptr2 = reinterpret_cast<T2 *>(&storage_)
> > ptr2->value/*scalar*/;
> >
> > > ([expr.ref] para. 8). Most (but not all) usual
> > > operations require that the dynamic type of the pointee actually
> > > matches the type of the pointer.
> >
> > I don't see how the above violates the sample below.
> > reinterpret_cast<T2 *>(&storage_)->....
>
> Look at [expr.ref] para. 8. The class member access 'ptr2->value' is
> illegal, regardless of what is done with that glvalue afterwards. The
> "strict aliasing" rule in [basic.lval] para. 11 only applies *after*
> that class member access is done, and even then it helps only if
> 'value' is a char, unsigned char, or std::byte.
>
> > The type of expression above is T* and that is what the *actual* result
> of reintepret_cast is as T2's object address should be equal to the address
> of storage_ and storage_ provides storage for T2's object which is in turn
> tested within storage_. Although I agree that std::launder would make it
> more explicit and I can be wrong on this.
> https://eel.is/c++draft/basic#intro.object-9
>
> The std::byte[sizeof(T)] array does provide storage for the T object,
> but this is irrelevant here, since the array object and the T object
> are not pointer-interconvertible. The only importance of providing
> storage is that the T object is nested within the array by
> ([intro.object] para. 4), so constructing the T object doesn't end the
> lifetime of the array ([basic.life] para. 1).
> --
> Std-Discussion mailing list
> Std-Discussion_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>

Received on 2023-08-06 17:20:15