匿名联合中类成员的初始化

initialization of class member in anonymous union

本文关键字:成员 初始化      更新时间:2023-10-16

我观察到ar.p():行出现以下代码分段故障

#include <iostream>
class A
{
public:
  virtual void p() { std::cout<<"A!n"; }
};
class B : public A
{
public:
  void p() { std::cout<<"B!n"; }
};
struct Param
{
  enum {AA, BB} tag;
  union {
    A a;
    B b;
  };
  Param(const A &p)
    : tag(AA) {a = p;}
  A &get() {
    switch(tag) {
    case AA: return a;
    case BB: return b;
    }
  }
};
int main() {
  A a;
  a.p();
  Param u(a);
  A &ar = u.get();
  ar.p();
}

但是,当我将Param构造函数更改为:时

Param(const A &p)
  : tag(AA), a(p) {}

它不再出错。

我认为这与工会成员a的vtable ptr的初始化方式有关,但我想更好地理解这个错误。

关于coliru:http://coliru.stacked-crooked.com/a/85182239c9f033c1

联合没有隐式构造函数,您必须将自己的构造函数添加到初始化联合的一个成员的联合中。我认为这是因为编译器不知道您是要初始化a还是b。您可能还需要一个赋值运算符和析构函数。另请参阅这个问题:如果联合的一个成员没有删除默认构造函数,为什么它会删除默认构造函数;什么都没有?

构造函数应该使用placement new,或者可以使用成员初始值设定项来构造一个联合成员,就像在备选构造函数中所做的那样。

如果之后要将某个内容分配给b,则必须使用a.~A()销毁a,然后使用placement new初始化b

如果联合中有具有非平凡析构函数的成员,则该联合必须具有一个析构函数,该析构函数调用当时使用的成员的析构函数。

在原始代码中,赋值运算符和p()方法在没有首先运行构造函数的情况下被调用,从而导致崩溃。