提问人:Fureeish 提问时间:9/7/2023 最后编辑:bitmaskFureeish 更新时间:9/7/2023 访问量:128
字节数组的 placement-new(隐式创建对象)是否会结束以前占用该存储的对象的生存期?
Does placement-new of array of bytes (which implictly creates objects) end the lifetime of the object that previously occupied that storage?
问:
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 有效。
int
float
但是,这些示例仍然没有根据拟议规则定义的行为。原因是 [basic.life]p4 的结果:
本文档中归因于对象和引用的属性仅适用于给定对象或引用的生存期。
具体来说,对象所持有的值仅在其整个生命周期内是稳定的。当第 #1 行中对象的生存期结束时(当第 #2 行中的
浮点
对象重用其存储时),其值将消失。对称地,在创建浮点对象时,该对象具有不确定的值 ([dcl.init]p12),因此任何加载其值的尝试都会导致未定义的行为。int
强调我的
该提案声称有问题的部分是对象的(隐式)创建。但是,前一行 () 不是已经重用了存储(通过创建数组),结束了相关存储的生命周期吗?根据我的理解,placement-new 总是结束内存中正在创建新对象的对象的生存期。float
new (buffer) std::byte[sizeof(buffer)]
byte
int
此外,此注释还指出,“新表达式不承诺保留存储中的字节。这是否意味着理论上可以改变字节,有效地摆脱我们希望双关语的值?new (buffer) std::byte[sizeof(buffer)]
buffer
需要明确的是,我不是在寻找一种实现类型双关的方法。这些只是最适合我(到目前为止我发现的)理解当今终身管理的潜在机制的例子。
答:
但是,上一行(new (buffer) std::byte[sizeof(buffer)])不是已经重用了存储(通过创建一个字节数组),结束了有问题的 int 的生命周期吗?
是的,尽管这是一个假设,因为对象只能通过隐式对象创建而存在,前提是程序可以通过隐式对象创建来定义行为,而它不会。int
无论哪种方式,结果都是一样的:如果对象的值是通过隐式对象创建而存在的,那么它将具有不确定的值,直到它被初始化/分配某个值,并且读取不确定的值将具有 UB。同一存储中上一个对象的值,无论是数组元素、嵌套对象还是数组元素,都不会影响新对象的初始值,无论是 还是 ,都在同一存储中。float
return *(float*)buffer;
char
int
std::byte
float
std::byte
因此,隐式对象创建无法从 UB 中保存程序。
评论
std::byte[sizeof(buffer)]
std::byte
new (buffer) std::byte[sizeof(buffer)]
int