1

我的目标是创建共享一些公共数据的类层次结构的类的实例。我创建(使用联合)足够的内存,以便可以在分配的内存中创建最大的实例。现在我想创建/交换类的实例并在那里使用内存中的“旧”数据。这是有效/合法的操作吗?

原始代码使用一些 MTP 东西来创建联合,目标是使用这个类层次结构作为状态机实现的核心。我在这里只显示包含问题的基本代码。

我看到如果基类不包含虚方法但派生方法包含,这是一个问题。这是因为 vtable 指针位于内存前面(在 x86/linux 上使用 gcc)。

简单的问题:如果基类的实例是之前创建的并且内存与该派生类的实例一起重用,那么派生类的实例能否访问基类的数据?

class Base
{
    public:
        int a;
        Base()=default;
        Base( int _a):a(_a){}

        void Print() { cout << "Value: " << a << endl; }
};

class Derived1: public Base
{
    public:
        int d;

        Derived1(): d( 0x11223344){}
};

union  U
{   
    U(){}
    Base base;
    Derived1 derived1;
} u;

int main()
{
    memset( &u, 0, sizeof(u));

    new (&u) Base(12345678);
    u.base.Print();

    new (&u) Derived1;
    u.base.Print();
 }
4

2 回答 2

1

不,这行不通,因为标准说:

9.5/1:在一个union中,最多一个非静态数据成员在任何时候都可以是活动的,即最多一个非静态数据成员的值可以随时存储在一个union中。

您尝试做的是未定义的行为:

new (&u) Derived1;  // RISKY !!!

使用placement new,您将覆盖之前在u 中的对象,而不会正确销毁它。然后创建Derived1无论如何都会创建自己的基础。如果您设法以某种方式将旧值保留在内存中,它仍然是未定义的行为:它可以工作或不工作,具体取决于编译器的对象布局和实现。

于 2015-04-25T12:40:43.090 回答
0

这是未定义的行为 - 它可能看起来有效,但不可移植且不应依赖。

一个工会只能有一个活跃成员;构建Derived1使之前发生的事情无效。

于 2015-04-25T12:40:51.713 回答