[Bug c++/95349] Using std::launder(p) produces unexpected behavior where (p) produces expected behavior

rguenth at gcc dot gnu.org gcc-bugzilla@gcc.gnu.org
Fri May 29 11:32:04 GMT 2020


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95349

--- Comment #11 from Richard Biener <rguenth at gcc dot gnu.org> ---
(In reply to Ed Catmur from comment #9)
> (In reply to Jonathan Wakely from comment #4)
> > I don't know the answer, and I don't know why it's useful to try this anyway.
> 
> If I'm reading P0593 correctly (I may not be), this would be a valid
> implementation of start_lifetime_as:
> 
> template<class T>
> inline T* start_lifetime_as(void* p) {
>     std::byte storage[sizeof(T)];
>     std::memcpy(storage, p, sizeof(T));
>     auto q = new (p) std::byte[sizeof(T)];
>     std::memcpy(q, storage, sizeof(T));
>     auto t = reinterpret_cast<T*>(q);
>     return std::launder(t);
> }
> 
> But this has the same issue: https://godbolt.org/z/YYtciP

I think there is no way to pun the dynamic type of an object without altering
its current storage representation.  You can do punning via a union but
that wouldn't change its effective type.

Note that for C++ types you can apply memcpy to the placement new is not
needed since object re-use terminates lifetime of the previous object and
starts lifetime of a new one.  This means that your example can be
simplified to

template<class T>
inline T* start_lifetime_as(void* p) {
 return reinterpret_cast<T*>(q);
}

easily showing why that cannot be the intention.

Note that while your example performs memcpy dances you are probably
after a solution that elides all generated code?

Note that I do not belive making your examples work as you intend is
possible in an actual implementation without sacrifying all
type-based alias analysis.


More information about the Gcc-bugs mailing list