C++ Logo

std-proposals

Advanced search

Re: Allowing access to object representations

From: Brian Bi <bbi5291_at_[hidden]>
Date: Mon, 19 Aug 2019 14:57:06 -0500
On Mon, Aug 19, 2019 at 2:15 PM <language.lawyer_at_[hidden]> wrote:

> On 19/08/2019 19:33, Brian Bi wrote:
> > On Sat, Aug 17, 2019 at 2:16 PM Language Lawyer via Std-Proposals <
> > std-proposals_at_[hidden]> wrote:
> >
> >> std::bless<std::byte[sizeof(T)]> (or how it is currently named), when it
> >> is added to the standard, will kinda allow accessing object
> representation
> >> without introducing very non-trivial changes to the C++ memory and
> object
> >> model.
> >
> > If I understand the std::bless approach properly, it has a serious
> > shortcoming: let's say T has some sufficiently nontrivial class type.
> Then,
> > the call to std::bless followed by reading from the std::byte array will
> > create the std::byte array, which *ends the lifetime of the *T since the
> T's
> > storage has now been reused by the std::byte array. If T is not an
> > implicit-lifetime type, then that means if you still want to use the
> > original T value *qua* T, then tough luck. If the T object had automatic
> > storage duration and a nontrivial destructor, then UB will happen when it
> > goes out of scope.
>
> Right, you'll need to recreate an object of type T using std::bless<T>
> when you're done accessing the array.
> (Note that you'll have to do this even if T is an implicit-lifetime type!)
>

I think if T is an implicit-lifetime type, the std::bless<std::byte[N]>
call can implicitly create the array first, and then implicitly create the T
object as well (so the array provides storage for the T object, and both
now coexist).
But if T is not an implicit-lifetime type, then calling std::bless<T>
afterward won't work. In fact, it's ill-formed, thanks to the "Mandates:"
clause. So in general there is no way to get the T object back, other than
calling a constructor, and obviously then you lose the ability to force the
object to hold the same value it previously held.

Plus, even if T *is* an implicit-lifetime type, the idea that you have to
destroy and recreate the object in order to observe its object
representation seems untenable. What happens if T contains a const member?
Now everyone who had access to that T object has to launder their pointers,
just because someone wanted to observe the object representation.


> > None of this would be a problem if we could just go back to the C++14
> > paradigm where we all agreed that every object of type T effectively
> > overlays objects of type char[T] and unsigned char[T] at the same address
> > (cf. CWG 1314).
>

Oh, my bad, I meant char[N] and unsigned char[N], where N is sizeof(T). I
guess that was pretty obvious though.


>
> I do not think that this is a good way.
>

What problem did this cause when it was effectively the status quo in
C++14, that is so serious that we should not attempt to codify it in C++23
or some future version of the standard?

-- 
*Brian Bi*

Received on 2019-08-19 14:59:21