2 ms·
That's interesting thanks, although just from the delta it is not obvious how it fix things; I'll have to read it eith the full context. So is launder needed f
by gpderetta 5y ago
That's interesting thanks, although just from the delta it is not obvious how it fix things; I'll have to read it eith the full context.
So is launder needed for anything now?
- tsimionescu 5y agoI will try to explain the logic as I understand it, and hopefully someone more knowledgeable will point out anyplace that I am wrong. The problematic code was this: struct X { const int n; }; union U { X x; float f; }; ... U u = {{ 1 }}; X *p = new (&u.x) X {2}; cout << u.x.n; //is this UB? After the placement new, we are in the case from this piece of the standard ("the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied"). u.x is "the name of the original object" - can we use it to manipulate the new object that placement new put in there? In the old standard, we can if "the type of the original object [...] does not contain any non-static data member whose type is const-qualified". Since X::n is const qualified, u.x can't be used to refer to the new object - enter std::launder. However, the new standard modifies this exception: we can still use u.x if "the original object is neither a complete object that is const-qualified nor a subobject of such an object". Neither u nor u.x are const-qualified objects, nor are they a sub-object of a const-qualified object. So, u.x now refers to the new object created by placement new. Still, std::launder seems to be needed for other cases, mostly related to reinterpret_cast. The C++ Reference site [0] shows these examples. [0] https://en.cppreference.com/w/cpp/utility/launder#Example https://en.cppreference.com/w/cpp/utility/launder#Example
- gpderetta 5y agoThanks for the explanation.