[英]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
. 我认为这是因为编译器无法知道您是否要初始化
a
或b
。 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.