C++ 新放置后,哪个工会成员变为活动成员

C++ 新放置后,哪个工会成员变为活动成员,c++,language-lawyer,unions,lifetime,placement-new,C++,Language Lawyer,Unions,Lifetime,Placement New,关于本守则: #include <string> int main() { union u { u() { i = 0; } ~u() {} int i; std::string s1; std::string s2; } u; new (&u) std::string{}; } #包括 int main() { 联合大学{ u(){i=0;} ~u(){} int

关于本守则:

#include <string>

int main()
{
    union u {
        u() { i = 0; }
        ~u() {}

        int i;
        std::string s1;
        std::string s2;
    } u;

    new (&u) std::string{};
}
#包括
int main()
{
联合大学{
u(){i=0;}
~u(){}
int i;
std::字符串s1;
std::字符串s2;
}u;
新(&u)标准::字符串{};
}

对象可以包含其他对象,称为子对象。子对象可以是成员子对象([class.mem])、基类子对象([class.derived])或数组元素。不是任何其他对象的子对象的对象称为完整对象如果在与成员子对象或数组元素e(可能在其生存期内,也可能不在其生存期内)关联的存储器中创建对象,则创建的对象是e的包含对象的子对象,如果:
-e的包含对象的生存期已开始,但尚未结束,并且
-新对象的存储正好覆盖了与e关联的存储位置,并且
-新对象的类型与e相同(忽略cv限定)

没有要求如何在与成员子对象关联的存储中创建对象。如果子对象是标准布局联合的成员或非联合类对象的第一个成员,则代码不必在运算符地址的参数中指定子对象。在这种情况下,只需获取包含对象的地址即可指定成员子对象的存储

«不要求如何创建对象»,除其他外,这意味着指定给placement new的指针不必指向子对象。主要是因为无法指向任何对象(注意,不要求子对象处于活动状态)。在std讨论邮件列表中,给出类型为
struct A{unsigned char buf[1];}的对象
x
,新(&x)a{}和新(x.buf)a{}之间有区别吗?在这两种情况下,
x.buf
都会对
A{}
产生负面影响。因为

[intro.object]和[basic.life]中的措辞涉及指针表示的存储地址,而不是指针指向的对象


发誓«在任何时候,联合类型的对象中最多有一个非静态数据成员可以处于活动状态»


在上面的代码中,
s1
还是
s2

指针是一个地址,但对于对象模型,它不仅仅是一个地址。它指向该地址处的特定对象。在某个地址可以存在多个对象,但这并不意味着指向其中任何一个对象的指针同时也是指向该地址上其他对象的指针。考虑[Exp.una.Op]/1关于指针间接方向的说明:

结果是一个左值,它引用表达式指向的对象或函数

不是“该地址的对象”;它是一个左值,指被指向的对象。显然,在C++对象模型中,多个对象可以存在于同一个地址,但是指向该地址的特定指针并不指向所有这些对象。它只指向其中一个

[expr.unary.op]/2表示“一元运算符和运算符的结果是指向其操作数的指针”。因此,
&u
指向
u
,它的类型是
u
(顺便问一下,是否真的需要将对象命名为与类型相同的名称?)
&u
不指向
u.i
u.s1
u.s2
。所有这些都保证与
&u
共享相同的地址,但
&u
本身只指向
u

现在的问题是,
&u
表示的存储是什么?根据[intro.object]/1,我们知道“一个对象占用一个存储区域”。如果
&u
指向对象
u
,则该指针必须表示该对象占用的存储区域。不存储其任何子对象;它是该对象的存储。整体而言

现在,我们进入
new(&u)std::string{}
。此表达式在由
&u
表示的存储器中创建类型为
std::string{}
的对象。表示重用对象
u
的存储。根据[basic.life]/1.4,终止
u
的生存期。终止其活动成员子对象的生存期


因此,您的问题的答案是,两者都不会变为活动状态,因为对象
u
不再存在。

您为什么在此处使用placement new,而不只是简单地分配给成员?这只是单纯的好奇,还是有一些潜在的问题?或者可能是某些现有的代码使用了此功能?@Someprogrammerdude赋值不会启动
std::string
类型的联合成员的生存期。要了解如何更改联合的活动成员,请参见以下内容:无论对话在此如何展开,这仍然是一个非常好的问题。我开始认为标准没有充分描述这种情况。希望有一位专家介入@语言律师:如果仍然没有足够的答案,请在几天后告诉我:我会悬赏回答这个问题。上周有一个类似的有趣的问题,关于新的布局(关于重新使用存储)。我认为整个功能在一些地方确实不够具体。@language律师:我不同意对标准的这种解释
[basic.life]
在这种解释下,关于联合的一切都失去了意义,因为根据这种推理,即使是
新的(&u.s1)std::string
也将应用于
u.s2
,因此两个子对象都将被激活,这是明确禁止的。因此,我选择标准有意义的解释。指针必须仅表示该对象指针值所占用的存储区域