https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95349
--- Comment #53 from Jonathan Wakely <redi at gcc dot gnu.org> --- (In reply to Ed Catmur from comment #9) > 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); > } I don't think this is correct, because it accesses the bytes (reading and writing them) which is not allowed ("the storage is not accessed). Implementing it this way would be a data race if two threads both use start_lifetime_as on the same memory at the same time. All of s1, s2 and s3 in the OP have the same problem. (In reply to Richard Smith from comment #20) > No, the new objects are allowed to replace existing objects. For example, > this implementation would also be correct: > > std::uint64_t* s3(double* p) { > std::memmove(p, p, sizeof(double)); > return std::launder(reinterpret_cast<std::uint64_t*>(p)); > } This works if and only if memmove(p, p, n) is optimized to not actually read or write any bytes (but still has the correct semantics of implicitly creating objects). If it's not optimized to not access the storage then it's a data race, and can't be used for the std::start_lifetime_as(const T*) overload. > ... on the basis that it has defined behavior if the memmove implicitly > creates an 'uint64_t' object in the underlying storage after it (notionally) > copies the contents elsewhere and before it (notionally) copies the contents > back again. (The 'launder' is necessary in order to form a pointer to the > implicitly-created uint64_t object, because p doesn't point to that object.) Couldn't you avoid the launder by returning static_cast<T*>(memmove(p, p, sizeof(T))) instead? That pointer _does_ point to the new object, doesn't it? ... huh, no, memcpy and memmove do not return a pointer to a suitable created object. Seems like they could/should.