[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