C++ union of derived classes with pure virtual base - what happens?

Viewed 36

I stumbled across this pattern today. It compiles fine but does not work correctly at runtime. ("Der1" is printed twice)

I can sort of see why, given that the address dereferenced is always the same, but I don't fully understand.

I am not looking for a solution or workaround, I have already restructured this code. Just interested to understand what happens under the hood in this scenario.

#include <iostream>

struct Base
{
    virtual void Func() = 0;
};

struct Der1 : public Base
{
    virtual void Func() override
    {
        std::cout << "Der1" <<std::endl;
    }
};

struct Der2 : public Base
{
    virtual void Func() override
    {
        std::cout << "Der2" <<std::endl;
    }
};

static union Ders
{
    Der1 D1;
    Der2 D2;
    Ders() : D1() {}
} theDers;

static Base * b = &theDers.D1;

int main()
{
    b->Func();
    b = &theDers.D2;
    b->Func();
    return 0;
}
1 Answers

What's happening is undefined behavior. What happens "under the hood" is immaterial. A different C++ compiler might produce completely different results (called a "crash").

You can observe undefined behavior in action by adding a constructor to both classes:

struct Der1 : public Base
{
    Der1()
    {
        std::cout << "Der1 construct\n";
    }

// ...

struct Der2 : public Base
{
    Der2()
    {
        std::cout << "Der2 construct\n";
    }

You will observe that only Der1 gets constructed. This is your big honking clue.

In a union, the first object in the union gets initially constructed for you. It becomes your onus to make a different member union "active" by manually invoking the existing active object's destructor and invoking the new active object's constructor, directly (typically using placement new). It's your onus to keep track of which union member is active.

The shown code invokes a method of an object that was never constructed, resulting in undefined behavior.

This is why in C++ it's much easier to use std::variant, which does all this work for you.

Related