是联盟成员的析构函数

Jon*_*Mee 21 c++ destructor unions standard-layout c++11

C++ 11允许在以下标准中使用标准布局类型union:Union的成员具有用户定义的构造函数

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

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

但是像这样的例子怎么样:

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

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

Nat*_*ica 17

在您的示例中,您提供的str不会被破坏.[class.union]/2中的标准状态

联合可以具有成员函数(包括构造函数和析构函数),但不具有虚函数(10.3).工会不得有基类.联合不得用作基类.如果联合包含引用类型的非静态数据成员,则程序格式错误.联合的至多一个非静态数据成员可以具有支撑或等于初始化器.[ 注意:如果union的任何非静态数据成员具有非平凡的默认构造函数(12.1),复制构造函数(12.8),移动构造函数(12.8),复制赋值运算符(12.8),移动赋值运算符(12.8),或者析构函数(12.4),联合的相应成员函数必须是用户提供的,否则将为联合隐式删除(8.4.3).- 结束说明 ]

强调我的

所以,因为两者strvec具有不平凡的,你需要为自己的工会为他们提供特殊的成员函数.

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

[...]如果X是联盟,其变体成员是非静态数据成员; [...]

因此,这个联盟的所有成员都是变体.然后,如果我们看一下[class.dtor]/8

在执行析构函数体并破坏正文中分配的任何自动对象之后,类X的析构函数调用X的直接非变量非静态数据成员的析构函数[...]

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

你可以做一个标签联合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();
   }
   ...
};
Run Code Online (Sandbox Code Playgroud)

这确保了正确的成员被破坏或只是使用std::variantboost::variant

  • @JonathanMee由于上面给出的引用,就标准而言.实际上,因为析构函数不会(总是)知道要调用哪个子对象析构函数. (3认同)
  • @JonathanMee我可以确保你删除了复制构造函数.标准甚至在下一段中有一个带有'std :: sting`的联合的例子,它表示*由于std :: string(21.3)声明所有特殊成员函数的非平凡版本,U将有一个隐式删除的默认构造函数,复制/移动构造函数,复制/移动赋值运算符和析构函数.要使用U,必须由用户提供部分或全部成员函数* (2认同)
  • @JonathanMee这些例子中没有编译器有任何内容.该初始化不涉及union的复制构造函数; union是一个聚合,这是聚合初始化(它确实涉及第一个union成员的复制初始化,`string`,它调用`string`的复制构造函数). (2认同)
  • @JonathanMee那些构造函数确实被删除了,但这并不一定意味着不可能构造.即使所有构造函数都被删除,聚合仍然可以通过聚合初始化进行初始化.这不仅限于工会.*特定于联合的*是联合聚合初始化被定义为初始化第一个成员.尝试将用户提供的构造函数添加到该联合; 比方说,像`S(){}`这样的默认构造函数.union将不再是聚合,初始化将不得不使用构造函数,这将失败. (2认同)
  • @NathanOliver我认为你是完全正确的避免他们;-).话虽如此,我不认为你使用的引用解释了为什么OP的代码不会调用`string`的析构函数; 毕竟,是的,工会的析构函数会被隐含地定义为删除,但他提供了一个; 为什么不起作用?我会说更好的引用在[\ [class.dtor \]/8](http://eel.is/c++draft/class.dtor#8); 关键词是*非变体*.变体成员的定义在[\ [class.union.anon \]/4](http://eel.is/c++draft/class.union#anon-4)中(联盟的成员是变体成员) . (2认同)
  • @JonathanMee更新. (2认同)
  • @bogdan 感谢您的引用。添加到答案中。 (2认同)