简体   繁体   English

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

[英]initialization of class member in anonymous union

I have observed that the following code segfaults at the line ar.p() : 我已经观察到以下代码段在ar.p()行中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();
}

However, when I change the Param constructor to: 但是,当我将Param构造函数更改为:

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

it does not segfault anymore. 它不再存在段错误。

I think it has something to do with the way the vtable ptr for union member a is initialized, but I'd like to understand this bug better. 我认为这与工会成员a的vtable ptr的初始化方式有关,但我想更好地理解此错误。

On coliru: http://coliru.stacked-crooked.com/a/85182239c9f033c1 在coliru上: http ://coliru.stacked-crooked.com/a/85182239c9f033c1

The union doesn't have an implicit constructor, you have to add your own constructor to the union which initializes one of the members of the union. 联合没有隐式构造函数,您必须将自己的构造函数添加到联合中,以初始化联合的成员之一。 I think this is because the compiler can't know whether you want to initialize a or b . 我认为这是因为编译器无法知道您是否要初始化ab You may also need an assignment operator and destructor. 您可能还需要赋值运算符和析构函数。 See also this question: Why does union has deleted default constructor if one of its member doesn't have one whatsoever? 另请参阅以下问题: 如果工会的成员之一没有任何成员,为什么会删除默认构造函数?

The constructor should use placement new or it can use a member initializer to construct one of the union members, as you do in your alternative constructor. 构造函数应该使用new放置,或者可以使用成员初始化程序来构造工会成员之一,就像在替代构造函数中所做的那样。

If you want to assign something to b afterwards, you have to destruct a using a.~A() , and then initialize b with placement new. 如果以后要向b赋值,则必须使用a.~A()破坏a ,然后使用new位置初始化b

If you have members in the union with a non-trivial destructor then the union must have a destructor which calls the destructor on the member which is used at that point. 如果联盟中的成员具有非平凡的析构函数,则该联盟必须具有一个析构函数,该析构函数调用此时使用的成员上的析构函数。

In your original code the assignment operator and the p() method are called without running a constructor first, leading to the crash. 在原始代码中,未首先运行构造函数就调用了赋值运算符和p()方法,从而导致崩溃。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM