是称为工会成员的析构函数

Is a Union Member's Destructor Called

本文关键字:成员 析构函数      更新时间:2023-10-16

c++ 11允许在union中使用标准布局类型:Member of Union has User-Defined Constructor

我的问题是:我保证自定义析构函数将被调用,当union超出作用域?

我的理解是切换时必须手动销毁和构造:http://en.cppreference.com/w/cpp/language/union#Explanation

但是像这样的例子呢:

{
    union S { string str;
              vector<int> vec;
              ~S() {} } s = { "Hello, world"s };
}

s超出作用域时,我是否因为没有调用string的析构函数而泄漏了在堆上分配的字符串的内存?

在您的示例中,您提供的str将不会被销毁。[class.union]/2

中的标准状态
联合可以有成员函数(包括构造函数和析构函数),但不能有虚函数(10.3)。联合不能有基类。联合不能用作基类。如果联合包含引用类型的非静态数据成员,则程序是病态的。联合中最多只能有一个非静态数据成员具有大括号或相等初始化式。[>注意:如果联合的任何非静态数据成员具有重要的默认构造函数(12.1)、复制构造函数(12.8)、移动构造函数(12.8)、复制赋值操作符(12.8)、移动赋值操作符(12.8)或析构函数(12.4),则联合的相应成员函数必须由用户提供,否则将为联合隐式删除(8.4.3)。- ]

<>共舞,强调我的

由于strvec都有特殊的成员函数,所以你需要自己为联合提供它们。

请注意,根据bogdan下面的注释,空析构函数是不够的。在类。Union]/8我们有

[…如果X是一个联合,它的变体成员是非静态数据成员;[…]

所以这个并集的所有成员都是变体。然后如果我们看[类。我们有

在执行析构函数体并销毁在析构函数体中分配的任何自动对象之后,类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::variantboost::variant

您的示例无法编译。默认情况下,联合具有一个已删除的析构函数。当然,应该调用什么析构函数?当然你不能两个都打。并且没有存储任何关于实际构造了哪个成员的信息。提供合适的析构函数取决于您。

下面是GCC在编译代码片段时的输出:

In function ‘int main()’:
error: use of deleted function ‘main()::<anonymous union>::~<constructor>()’
       vector<int> vec; } s = { "Hello, world"s };
                                                ^
note: ‘main()::<anonymous union>::~<constructor>()’ is implicitly deleted because the default definition would be ill-formed:
      union { string str;
            ^

总是需要用非平凡类型手动调用结构中对象的构造函数。

通常也需要显式地构造它们。这里的赋值工作起来似乎很奇怪。

如果有疑问,您可以在调用析构函数时检查程序集。

这段代码的程序集调用basic_string构造函数,但不调用析构函数。所以这里会有漏洞。

using namespace std;
int main(int argc, char** argv){
    union S { string str;
              vector<int> vec;
              ~S() {} } s = { "Hello, world"s };
}

链接查看程序集:https://godbolt.org/g/wKu3vf