On Mon, Aug 19, 2019 at 2:15 PM <language.lawyer@gmail.com> 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@lists.isocpp.org> 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