将新 U 放置在现有 T 对象上并对其进行操作是 UB?

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

在此 link 中,存储重用 部分显示了以下示例。

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

,其中一个答案包含此代码。

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...

    // ...
}

以上都是尝试在现有对象上执行placement new another type,第二个代码是操作新对象。

但是,the first link说的是下面的话

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)

根据强调句,第二个例子是undefined behavior,因为新对象类型和旧对象类型不一样,d[0] = 1.;操作新对象
但是,没有人在评论中指出这个问题..所以我很困惑。

  1. 第一个示例是否定义了行为,因为它只是执行新的放置?
  2. 第二个例子是不是因为UB所以错了?

我是不是误会了什么..?

两个例子都是合法的。

“透明可替换性”仅在您想使用指向旧对象的指针访问新对象而不需要 std::launder 时才重要。

但你没有那样做。您正在使用 placement-new 返回的指针(不是指向旧对象的指针)操作新对象,它永远不需要 std::launder.