C++ Logo

std-discussion

Advanced search

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

From: Ville Voutilainen <ville.voutilainen_at_[hidden]>
Date: Tue, 1 Aug 2023 03:21:06 +0300
On Tue, 1 Aug 2023 at 02:33, Thiago Macieira via Std-Discussion
<std-discussion_at_[hidden]> wrote:
>
> On Monday, 31 July 2023 14:01:11 PDT Bjorn Reese via Std-Discussion wrote:
> > > I can't figure out if the second application is valid in general, or is
> > > it UB? It seems that the standard of the language through prescriptions
> >
> > Undefined behaviour. See https://wg21.link/p2590
>
> I just want to point out that I disagree with the premises of the paper above.

I don't understand why start_lifetime_as is brought up in this
discussion, and where that paper shows
the example in the beginning of the thread being UB. start_lifetime_as
convinces the language that a bag of representation bits
are a valid object of trivial type. But the example in the
thread-starting message is not like that at all, it does a placement
new of a T object into a storage location, and then separately obtains
a pointer to T into that same storage location.
If the status quo wording somewhere says that's UB, then we should
have an almost trivial issue submission saying "surely not".
That should also have nothing to do with start_lifetime_as, because
that placement-new plus the later address-obtaining and use
should work even for non trivial types, for any T, regardless of
whether trivial or complex, so start_lifetime_as doesn't solve
any problems here anyway.

> The paper says these reinterpret_cast are UB:
>
> void process(Stream* stream) {
> std::unique_ptr<char[]> buffer = stream->read();
> if (buffer[0] == FOO)
> processFoo(reinterpret_cast<Foo*>(buffer.get()));
> else
> processBar(reinterpret_cast<Bar*>(buffer.get()));
> }
>
> But the standard also says that memcpy() is allowed to implicitly create
> objects, something this paper even reminds us of. Since any read() implies a
> memcpy() from some other storage, I argue that the object's lifetime was
> already started.

Well, there's a limited bunch of special functions that the standard
recognizes as implicit-lifetime-starting.
malloc is one of them, memcpy is another, but not all operations that
copy memory are in that bunch.
That's why we need start_lifetime_as, to be able to provide an escape
hatch to communicate to the language
that such a special operation is in play, even though the standard
doesn't explicitly recognize it as such,
and that also makes that bunch extensible.

Received on 2023-08-01 00:21:20