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)