Is it Undefined Behavior to call virtual functions of union member with a common base class as another member?
Asked Answered
U

0

7

Specifically, I would like to be able to use polymorphism without heap allocation in an embedded context (thus without dynamic allocation). My concern here seems to be that accessing the base member while x or y are "active" in the union seems to be an instance of type-punning, even though they share the same initial header (and vtable structure). Would the code below be considered defined behavior?

#include <iostream>
#include <new>

using namespace std;

struct Base {
    virtual const char *foo() { return "base"; }
};

struct X: public Base {
    const char *foo() override { return "d1"; }
};

struct Y: public Base {
    const char *foo() override { return "d2"; }
};

union DerivedAny {
    DerivedAny() {}
    Base& get() { return *launder(&b); }
    Base b = {};
    X x;
    Y y;
};

DerivedAny objs[3];

int main() {
    new (&objs[1].x) X;
    new (&objs[2].y) Y;
    cout << objs[0].get().foo() << endl;
    cout << objs[1].get().foo() << endl;
    cout << objs[2].get().foo() << endl;
}

I've compiled it with both GCC and Clang and they to appear to return the expected output in both cases:

base
d1
d2
Unshackle answered 10/6, 2019 at 19:54 Comment(4)
I am pretty sure your analysis is correct. Accessing inactive member of the union is UBLyontine
I think what you're trying to solve might be better if you implement your own polymorphism instead on relying on virtual functionsBottleneck
Have you considered std::variant and visit?Vaios
std::variant and std::visit doesn't seem too scalable, and std::visit, being essentially a switch statement, somewhat defeats the idea of using polymorphism in the first place.Unshackle

© 2022 - 2024 — McMap. All rights reserved.