3 ms·
The constiness of a pointer can be casted away while the constiness of a value variable cannot — it’s UB. foo::x is declared const, so it’s always const.
by ptr 5y ago
The constiness of a pointer can be casted away while the constiness of a value variable cannot — it’s UB.
foo::x is declared const, so it’s always const.
- codeflo 5y agoI realize that, but no variable is const, only the field is. And you don’t need a const_cast to change the value, as the example in the question shows, some_func can do: void some_func(foo *p) { new(p) foo { 42 }; } That’s not UB.
- bingo3131 5y agoIt is UB as the original object has non-static data members that are const-qualified.
- codeflo 5y agoI don’t think so. According to https://stackoverflow.com/a/39382728 https://stackoverflow.com/a/39382728 (the original SO answer that prompted the linked SO question, and which quotes the relevant parts of the spec), the allocation is not UB, but accessing the member after that (at least without the std::launder trick) is UB. It’s precisely this latter part that I don’t think is very reasonable to have in the spec.
- gpderetta 5y agoNote that accessing the new object via the pointer to placement new is perfectly fine, the issue is dereferencing the old pointer that logically point to an object whose lifetime has been terminated even if it mught actually contain the same bit pattern as the new pointer. I think this is related to the ill-defined concept of pointer provenance. 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).
- bingo3131 5y agoThe issue is that code outside of some_func does not know that f has been destroyed and a new object created in the same memory location, thus wouldn't know that the const member foo::x now has a new value. 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.
- ectopod 5y agoFrom the article: > 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.
- sutuplesu 5y ago> you cannot access the new object through pointers to the old The access in the caller -- `return f.x` -- is not through a pointer.