void some_func(foo *p) {
new(p) foo { 42 };
}
That’s not UB. void some_func(foo *p) {
new(p) foo { 42 };
}
That’s not UB.> if you allocate a new object in the storage of the old one, you cannot access the new object through pointers to the old
Which implies the UB happens in the caller.
The access in the caller -- `return f.x` -- is not through a pointer.
As for why the spec prohibits the modification of const values: one of the reasons for compilers being allowed to treat const values as being truly immutable is for performance. If the compiler can see the actual value then it can avoid the memory read entirely, and if it doesn't know the actual value then it only needs to do one memory read.
If those const values could change without the compiler being aware then it now needs to do an awful lot more fetching from memory as it cannot guarantee that the value did not change. Some of it could be optimized away, but it would still make code a lot slower if - for example: mixing reads from const ints with pointer/reference manipulation of ints - as due to potential aliasing the compiler would likely have to read those const ints from memory each time.
Launder let you discard any provenance info for the old pointer and treat it as a new one.
Tricky and very ill-defined, and according to the another comment elsethread this now doesn't require launder anymore (it probably was proven unworkable in practice).