放置新对象是否会启动对象的生命周期?

Doc*_*sha 9 c++ c++17 stdlaunder

以下代码示例来自 cppreference 上std::launder

alignas(Y) std::byte s[sizeof(Y)];
Y* q = new(&s) Y{2};
const int f = reinterpret_cast<Y*>(&s)->z; // Class member access is undefined behavior
Run Code Online (Sandbox Code Playgroud)

在我看来,由于标准中的[basic.life]/6,第三行将导致未定义的行为:

在对象的生命周期开始之前,但在分配对象将占用的存储空间之后...如果...指针用于访问非静态数据成员或调用非静态,则程序具有未定义的行为对象的成员函数。

为什么placement new没有开始object的生命周期Y

use*_*522 12

placement-new 确实启动了Y对象(及其子对象)的生命周期。

但对象的生命周期并不是std::launder重点。std::launder不能用于启动对象的生命周期。

std::launder当您有一个指针指向与该指针类型不同的类型的对象时使用,当您reinterpret_cast指向一个类型的指针不存在目标类型的对象时,会发生这种情况以前的对象。

std::launder然后可以(假设满足其先决条件)用于获取指向位于指针引用的地址的指针类型(必须已经在其生命周期内)的对象的指针。

&s是一个指向sizeof(Y) std::bytes 数组的指针。还有一个显式创建的Y对象与该数组共享地址,并且该数组为该对象提供存储Y。但是,数组(或数组元素)不能与其提供存储的对象进行指针互换。因此,结果reinterpret_cast<Y*>(&s)不会指向Y对象,但仍指向数组。

如果使用的左值实际上并不引用与左值类型(类似)的对象,则访问成员具有未定义的行为,这里的情况是左值引用数组,而不是对象Y

因此,要获取指向与其生命周期内Y位于同一地址的对象的指针和左值,您需要首先调用:&sstd::launder

const int f = std::launder(reinterpret_cast<Y*>(&s))->z;
Run Code Online (Sandbox Code Playgroud)

当然,所有这些复杂性都可以通过直接使用返回的指针来避免new。它已经指向新创建的对象:

const int f = q->z;
Run Code Online (Sandbox Code Playgroud)