[Bug c++/95349] Using std::launder(p) produces unexpected behavior where (p) produces expected behavior
andrew2085 at gmail dot com
gcc-bugzilla@gcc.gnu.org
Mon Nov 14 04:53:49 GMT 2022
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95349
--- Comment #44 from Andrew Downing <andrew2085 at gmail dot com> ---
(In reply to Richard Biener from comment #43)
> (In reply to Andrew Downing from comment #41)
> > > Thus for types without a non-trivial ctor/dtor you do not need to use
> > > placement new. So take your example and remove the placement new.
> > > Does that change its semantics?
> >
> > These are C++17 rules.
> >
> > 4.5/1) An object is created by a definition, by a new-expression, when
> > implicitly changing the active member of a union, or when a temporary object
> > is created.
> >
> > 6.8/1) The lifetime of an object of type T begins when: storage with the
> > proper alignment and size for type T is obtained, and if the object has
> > non-vacuous initialization, its initialization is complete.
> >
> > double d;
> >
> > My interpretation of the above rules would be that only a double object is
> > created in the storage for d because T in 6.8/1 is set to double by the
> > definition of d. According to these rules the only way to change the dynamic
> > type of the object in d's storage would be with placement new (pre C++20).
> > memcpy only overwrites the object representation. It doesn't affect it's
> > type or lifetime.
>
> What would
>
> *(long *)&d = 1;
>
> do? My reading of earlier standards say it starts lifetime of a new object
> of type long (the storage of 'd' gets reused). Following that stmt a read
> like
>
> foo (d);
>
> invokes undefined behavior (it accesses the storage of effective type long
> via an effective type of double). The same example with placement new
> would be
>
> *(new (&d) long) = 1;
>
> and I'm arguing the placement new is not required to start the lifetime
> of an object of type long in the storage of 'd'.
It's been a while since I've though about this stuff.
double d;
*(long *)&d = 1;
That would be lead to undefined behavior because it's breaking the strict
aliasing rules.
*(new (&d) long) = 1;
That would be ok because new creates a long object in the storage of d before
dereferencing.
More information about the Gcc-bugs
mailing list