在您提供的示例中,str
不会被破坏。[class.union]/2 中的标准状态
联合可以具有成员函数(包括构造函数和析构函数),但不能具有虚拟 (10.3) 函数。联合不应有基类。联合不应用作基类。如果联合包含引用类型的非静态数据成员,则程序格式错误。最多一个联合的非静态数据成员可以有一个大括号或相等初始化器。[注意:如果联合的任何非静态数据成员具有非平凡的默认构造函数 (12.1)、复制构造函数 (12.8)、移动构造函数 (12.8)、复制赋值运算符 (12.8)、移动赋值运算符 (12.8),或析构函数(12.4),联合的相应成员函数必须是用户提供的,否则它将为联合隐式删除(8.4.3)。——尾注]
强调我的
因此,由于两者str
和vec
都有特殊的成员函数,你需要自己为联合提供它们。
请注意,根据bogdan在空析构函数下方的评论是不够的。在 [class.union]/8 我们有
[...]如果 X 是一个联合,它的变体成员是非静态数据成员;[...]
所以这个联盟的所有成员都是变种。然后,如果我们查看 [class.dtor]/8 我们有
在执行析构函数的主体并销毁主体内分配的任何自动对象后,类 X 的析构函数调用 X 的直接非变体非静态数据成员的析构函数[...]
所以析构函数不会自动销毁联合的成员,因为它们是变体。
你可以像kennytm在这里做一个带标签的联合
struct TU {
int type;
union {
int i;
float f;
std::string s;
} u;
TU(const TU& tu) : type(tu.type) {
switch (tu.type) {
case TU_STRING: new(&u.s)(tu.u.s); break;
case TU_INT: u.i = tu.u.i; break;
case TU_FLOAT: u.f = tu.u.f; break;
}
}
~TU() {
if (tu.type == TU_STRING)
u.s.~string();
}
...
};
这确保正确的成员被破坏或只使用std::variant
或boost::variant