字节数组的放置新(隐式创建对象)是否会结束先前占用该存储的对象的生命周期?

Fur*_*ish 6 c++ lifetime placement-new language-lawyer c++23

P0593,在类型双关部分下,展示了这个例子:

float do_bad_things(int n) {
  alignof(int) alignof(float)
    char buffer[max(sizeof(int), sizeof(float))];
  *(int*)buffer = n;      // #1
  new (buffer) std::byte[sizeof(buffer)];
  return *(float*)buffer; // #2
}
Run Code Online (Sandbox Code Playgroud)

并指出:

提议的规则将允许一个int对象突然出现以使第 #1 行有效 [...],并且将允许一个float对象同样突然出现以使第 #2 行有效。

然而,这些示例在提议的规则下仍然没有定义行为。原因是 [basic.life]p4 的结果:

本文档中赋予对象和引用的属性仅在给定对象或引用的生命周期内适用。

具体来说,对象所持有的值仅在其整个生命周期内保持稳定。int当第 #1 行中的对象的生命周期结束时(当第 #2 行中的对象重用其存储时float),它的值就消失了。对称地,当创建 float 对象时,该对象具有不确定的值 ([dcl.init]p12),因此任何加载其值的尝试都会导致未定义的行为。

强调我的

该提案声称有问题的部分是float对象的(隐式)创建。但是上一行 ( new (buffer) std::byte[sizeof(buffer)]) 不是已经重用了存储(通过创建数组),结束了相关byte的生命周期吗?int据我了解,安置总是新的结束内存中创建新对象的对象的生命周期。

另外,这个评论说“新表达式不承诺保留存储中的字节。 ”这是否意味着new (buffer) std::byte[sizeof(buffer)]理论上可以改变 的字节buffer,有效地消除我们希望双关的值?

需要明确的是,我并不是在寻找一种实现类型双关的方法。这些只是最适合我(到目前为止我发现的)理解当今生命周期管理的基本机制的例子。

use*_*522 0

但是上一行 (new (buffer) std::byte[sizeof(buffer)]) 不是已经重用了存储(通过创建字节数组),结束了相关 int 的生命周期吗?

是的,尽管这是一个假设,因为int如果程序通过隐式对象创建给出定义的行为,则该对象只能通过隐式对象创建而存在,但事实并非如此。

无论哪种方式,结果都是相同的:float如果对象的值是通过隐式对象创建而存在的,则该对象的值将具有不确定的值,直到它被初始化/分配一些值并使用return *(float*)buffer;UB 读取不确定的值。同一存储中先前对象的值,无论是char数组元素、int嵌套对象还是std::byte数组元素,都不会影响同一存储中的新对象(无论float是)的初始值。std::byte

所以隐式对象创建并不能从UB中保存程序。