如果可能的话,如何在联合本身初始化之后初始化联合成员?
struct U_Keeper
{
U_Keeper() : x();
bool HoldingTypeU {true};
union
{
X x;
Y y;
};
};
void doSomething(){
U_Keeper uk;
doSomethingWithX(uk.x);
// set uk to Y mode and initialize uk.y
uk.HoldingTypeU = false;
};
假设Y是一个复杂的大类型,需要初始化。你会怎么做呢?
我问这个问题的原因是:我有一个这样的联合"Y"是std::string
。当然,std::string
有一个赋值操作符,所以它的值可以稍后设置。但我不确定std::string
是否需要初始化,除了稍后是否会分配给它。也许当一个std::string
被分配给它时,它建立在它已经拥有的数据之上:它覆盖了已经存在的数据,因此已经需要一个有效的指针指向数据。
如果联合成员是微不足道的,激活成员的传统方法是分配它:
uk.y = some_value;
如果成员是非平凡的(如std::string
),那么您必须首先销毁当前活动的成员,然后使用placementnew:
uk.x.~X();
::new (&uk.y) Y /*parenthesised or braced init arguments here*/;
注意,如果联合包含非平凡成员,则除默认构造函数外,从析构函数到复制构造函数再到赋值操作符的所有特殊成员函数都将被隐式删除。因此,您需要为包装它的类定义这些属性。每个人都必须知道当前活跃的成员,并采取相应的行动。
还要注意析构函数不像普通类那样隐式地销毁联合成员,后者会在析构函数体之后销毁成员。这必须像上面所示的那样明确地完成。
注:在标准库中有一个标准标记联合:std::variant
。不需要你自己发明。