【发布时间】:2019-06-11 17:06:21
【问题描述】:
关于此代码:
#include <string>
int main()
{
union u {
u() { i = 0; }
~u() {}
int i;
std::string s1;
std::string s2;
} u;
new (&u) std::string{};
}
[intro.object]/2 这么说
对象可以包含其他对象,称为子对象。子对象可以是成员子对象 ([class.mem])、基类子对象 ([class.derived]) 或数组元素。不是任何其他对象的子对象的对象称为完整对象。 如果在与成员子对象或数组元素 e 关联的存储中创建对象(可能在或不在其生命周期内),则创建的对象是 e 的包含对象的子对象,如果:
— e 的包含对象的生命周期已经开始但没有结束,并且
— 新对象的存储正好覆盖与 e 关联的存储位置,并且
— 新对象与 e 的类型相同(忽略 cv 限定)。
没有要求如何在与成员子对象关联的存储中创建对象。如果子对象是标准布局联合的成员或非联合类对象的第一个成员,则代码不必在地址运算符的参数中指定子对象。在这种情况下,获取包含对象的地址来指定成员子对象的存储就足够了。
«没有如何创建对象的要求»,除其他外,意味着赋予放置 new 的指针不必指向子对象的point。主要是因为可能没有对象可以指向(注意,[intro.object]/2 不需要子对象处于活动状态)。在标准讨论邮件列表中,有人问,给定一个类型为struct A { unsigned char buf[1]; }; 的对象x,new (&x) A{} 和new (x.buf) A{} 之间有区别吗?而the answer 不是,在这两种情况下,x.buf 将provide storage 用于A{}。因为
[intro.object] 和 [basic.life] 中的措辞与指针表示的存储地址有关,而不是它指向的对象。
[class.union]/1 发誓«联合类型对象的最多一个非静态数据成员可以随时处于活动状态»。
在上面的代码中,哪个激活了,s1 或 s2?
【问题讨论】:
-
你在这里使用placement new而不是简单地分配给成员的原因是什么?只是单纯的好奇,还是有一些潜在的问题?或者可能是一些使用它的现有代码?
-
@Someprogrammerdude 赋值不会启动
std::string类型的联合成员的生命周期。 -
要了解如何更改工会的活跃成员,请参阅:stackoverflow.com/questions/46349720/…
-
不管这里的对话如何发展,这仍然是一个非常好的问题。我开始认为该标准没有充分描述这种情况。希望专家介入。@LanguageLawyer:如果仍然没有足够的答案,请在几天内给我打电话:我会悬赏这个问题。
-
上周有一个类似的有趣问题,即关于放置新的更普遍的问题(关于重用存储)。我认为整个功能在某些地方确实没有得到充分说明。
标签: c++ language-lawyer unions lifetime placement-new