字节数组的 placement-new(隐式创建对象)是否会结束以前占用该存储的对象的生存期?

Does placement-new of array of bytes (which implictly creates objects) end the lifetime of the object that previously occupied that storage?

提问人:Fureeish 提问时间:9/7/2023 最后编辑:bitmaskFureeish 更新时间:9/7/2023 访问量:128

问:

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
}

并指出:

拟议的规则将允许一个对象出现,使行 #1 有效 [...],并允许一个对象同样出现,使行 #2 有效。intfloat

但是,这些示例仍然没有根据拟议规则定义的行为。原因是 [basic.life]p4 的结果:

本文档中归因于对象和引用的属性仅适用于给定对象或引用的生存期。

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

强调我的

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

此外,此注释还指出,“新表达式不承诺保留存储中的字节。这是否意味着理论上可以改变字节,有效地摆脱我们希望双关语的值?new (buffer) std::byte[sizeof(buffer)]buffer

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

C++ 语言-律师 终身 安置-新 C++23

评论

0赞 Swift - Friday Pie 9/7/2023
我不会说放置新是一种隐含的创造。这是相当明确的。这是 std::malloc whch 隐式创建。您应该保存它返回的指针并使用它
0赞 Fureeish 9/7/2023
@Swift-FridayPie,我从来没有说过 placement-new 会隐含地创造任何东西。在本例中,创建数组会隐式创建对象。无需保存指向它的任何指针。此外,我看不出这与问题如何一致。不过,也许标题有点误导std::byte[sizeof(buffer)]
0赞 Language Lawyer 9/7/2023
结束所讨论的 int 的生命周期?是的,这是正确的。有效地摆脱了我们希望双关语的价值?new-expression 创建的对象(及其子对象)具有动态存储持续时间,timsong-cpp.github.io/cppwp/n4868/basic.indet#1 应用于数组元素std::byte
0赞 Fureeish 9/7/2023
@LanguageLawyer这意味着可以保证保留(现已死亡)的价值?new (buffer) std::byte[sizeof(buffer)]int
0赞 Language Lawyer 9/7/2023
timsong-cpp.github.io/cppwp/n4868/basic.indet#1 如何保证这一点?

答:

0赞 user17732522 9/7/2023 #1

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

是的,尽管这是一个假设,因为对象只能通过隐式对象创建而存在,前提是程序可以通过隐式对象创建来定义行为,而它不会。int

无论哪种方式,结果都是一样的:如果对象的值是通过隐式对象创建而存在的,那么它将具有不确定的值,直到它被初始化/分配某个值,并且读取不确定的值将具有 UB。同一存储中上一个对象的值,无论是数组元素、嵌套对象还是数组元素,都不会影响新对象的初始值,无论是 还是 ,都在同一存储中。floatreturn *(float*)buffer;charintstd::bytefloatstd::byte

因此,隐式对象创建无法从 UB 中保存程序。