This is a followup on the answers for placement new on a class with reference field.
Calling std::vector<A>::data()
on type A
that has reference or const fields, returns a pointer to objects that may be changed through the original vector by placement new, which causes a const or reference field of an original object to be replaced, while still being managed by another pointer, returned via the call to data()
.
For example:
struct A {
const int i = 0;
};
int main() {
std::vector<A> vec = {{1}, {2}};
auto ptr = vec.data();
std::cout << ptr[1].i << std::endl; // 2
vec.pop_back();
vec.push_back({3}); // placement new, inside
std::cout << ptr[1].i << std::endl; // 3
}
C++17 tried to resolve such issues by introducing std::launder
but it was later agreed that while std::launder
may solve other issues, it doesn't really solve the problem for above use case as noted in NB US042.
Some questions - for C++ versions prior to C++20:
Since NB US042 was accepted as a change for C++20 spec, but not marked as a DR - would it be advised, according to the spec only, to avoid the use of
std::vector<A>::data()
on a typeA
that has reference or const fields as in above example?Or, the wording of the spec for
std::vector<>::data()
covers that, making it legal and leaving the implementability question to the library implementers?If it is the latter, what can the library do to make it legal?
If it can't really do anything useful to make it legal, is it UB before C++20?
If it is UB before C++20, why wasn't this change considered to be a candidate for a DR, same as p0593r6? Most probably compilers do the right thing anyway, why not mandate that retroactively?