Search code examples
c++strict-aliasingplacement-new

Placement New U on existing T object and Manipulating it is UB?


In this link, Storage reuse section shows the following example.

void x()
{
    long long n; // automatic, trivial
    new (&n) double(3.14); // reuse with a different type okay
} // okay

and here, one of the answers contains this code.

void f(float* buffer, std::size_t buffer_size_in_bytes)
{
    double* d = new (buffer)double[buffer_size_in_bytes / sizeof(double)];

    // we have started the lifetime of the doubles.
    // "d" is a new pointer pointing to the first double object in the array.        
    // now you can use "d" as a double buffer for your calculations
    // you are not allowed to access any object through the "buffer" pointer anymore since the // floats are "destroyed"       
    d[0] = 1.;
    // do some work here on/with the doubles...

    // ...
}

All the above are trying to perform placement new another type on the existing object, and the second code is manipulating the new object.

But, the first link is saying the following

If a new object is created at the address that was occupied by another object, then all pointers, references, and the name of the original object will automatically refer to the new object and, once the lifetime of the new object begins, can be used to manipulate the new object, but only if the original object is transparently replaceable by the new object.

Object x is transparently replaceable by object y if:

  • the storage for y exactly overlays the storage location which x occupied
  • y is of the same type as x (ignoring the top-level cv-qualifiers)

According to the emphasized sentence, the second example is undefined behavior because the new object type is not the same as the old one, and d[0] = 1.; manipulates the new object.
But, no one stated this problem in the comments.. so I'm confused.

  1. Is the first example defined behavior because it just performs placement new?
  2. Is the second example wrong because of UB?

Am I misunderstanding something..?


Solution

  • Both examples are legal.

    "Transparent replaceability" only matters when you want to use a pointer to the old object to access the new object without std::launder.

    But you're not doing that. You're manipulating the new object using the pointer returned by placement-new (not a pointer to the old object), which never needs std::launder.