是否调用了 Union 成员的析构函数

Is a Union Member's Destructor Called

C++11 允许在 union 中使用标准布局类型:

我的问题是:当 union 超出范围时,我是否保证会调用自定义析构函数?

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

但是像这样的例子呢:

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

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

您的示例无法编译。默认情况下,联合具有删除的析构函数。因为当然,应该调用什么析构函数?当然你不能同时调用两者。并且没有任何地方存储关于哪个成员实际构建的任何信息。由您提供合适的析构函数。

这是尝试编译您的代码片段时 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;
            ^

在您提供的示例中 str 不会被破坏。 [class.union]/2

中的标准状态

A union can have member functions (including constructors and destructors), but not virtual (10.3) functions. A union shall not have base classes. A union shall not be used as a base class. If a union contains a non-static data member of reference type the program is ill-formed. At most one non-static data member of a union may have a brace-or-equal-initializer . [ Note: If any non-static data member of a union has a non-trivial default constructor (12.1), copy constructor (12.8), move constructor (12.8), copy assignment operator (12.8), move assignment operator (12.8), or destructor (12.4), the corresponding member function of the union must be user-provided or it will be implicitly deleted (8.4.3) for the union. — end note ]

强调我的

因此,由于 strvec 都有特殊的成员函数,您需要自己为 union 提供它们。

请注意,根据下面的 bogdan's 评论,空析构函数是不够的。在 [class.union]/8 中我们有

[...]If X is a union its variant members are the non-static data members;[...]

所以这个联盟的所有成员都是变体。然后,如果我们查看 [[=​​42=]]/8,我们有

After executing the body of the destructor and destroying any automatic objects allocated within the body, a destructor for class X calls the destructors for X’s direct non-variant non-static data members[...]

因此析构函数不会自动销毁联合体的成员,因为它们是变体。

你可以做一个tagged union like kennytm does here

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

您始终需要手动调用具有非平凡类型的结构中对象的构造函数。

通常你也总是需要显式地构造它们。这里的作业似乎很奇怪。

如有疑问,您可以随时检查程序集是否调用了析构函数。

此代码的程序集确实调用了 basic_string 构造函数而不是析构函数。所以你这里会有漏洞。

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

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