C++ Undefined Behavior – How to Handle Undefined Behavior in Vector Access

c++stdlaunderundefined-behavior

Following up the p0532r0.pdf documentation the following piece of code results in UB

#include <iostream>
#include <vector>
struct X {
    const int i;
    X(int _i) : i(_i) {}
    friend std::ostream& operator<< (std::ostream& os, const X& x) {
    return os << x.i;
    };
};
int main(){
    std::vector<X> v;
    v.push_back(X(42));
    v.clear();
    v.push_back(X(77));
    std::cout << v[0]; // undefined behaviour
}

However no UB is detected when the above piece of code is run with sanitiser.
demo
Why does compiler not detect this error? Apart from that based on the P0532R0, when type of vector is a class that has a const member , the internal usage of placement new causes UB. How is this issue overcome ?

Best Answer

the internal usage of placement new causes UB

If the compiler uses placement new to overwrite the vector's first element this is no longer UB as of C++ 20. Placement new is allowed to "transparently replace" const values so long as it is not a top level const. Also, std::launder is no longer needed for access. See basic life for details on transparent replacement.

However, the copy assignment operator is automatically deleted so the vector object can no longer be resized for instance by adding additional elements that exceed the vector's capacity.

See this discussion on how to write a custom copy assigment operator to handle classes with const or reference objects.