0

Say, we would like to access members of a C++ structure by indices. It could be conveniently implemented using unions:

#include <iostream>

struct VehicleState
{
    struct State
    {
        double x, y, v, yaw;
    };

    union
    {
        State st;
        double arr[4];
    };
};


int main()
{
    VehicleState state;
    state.st.x = 1;
    state.st.y = 2;
    state.st.v = 3;
    state.st.yaw = 4;
    for (auto value : state.arr)
        std::cout << value << std::endl;
}

Unfortunately, it is undefined behavior to read from the member of the union that wasn't most recently written. That said, I haven't found any compiler or a platform where it would not work as expected. Could you tell me what was the rationale for calling it undefined behavior rather than standardizing it?

mentalmushroom
  • 2,261
  • 1
  • 26
  • 34
  • How should that be standardized?? – πάντα ῥεῖ Jul 24 '22 at 09:31
  • When answering πάντα ῥεῖ please make sure you account for *all* types that can appear in a union, `std::string`, `std::thread` and any user defined type with any invariant it can have. – StoryTeller - Unslander Monica Jul 24 '22 at 09:34
  • I think it has to do with the fact that union members can also be classes, in some cases it must be possible for those members to be created implicitly at fist assignment, before that they will not be in a usable state. – Pepijn Kramer Jul 24 '22 at 09:36
  • No we would most definitely NOT like to access members of a C++ structure by indices. Why? Something that should be accessed by indices is an array. So what if the index is sometimes a constant? If `state[3]` goes against your aesthetic feelings, write `state[yaw]` where `yaw` is defined as `3` somewhere. – n. m. could be an AI Jul 24 '22 at 09:37
  • Perhaps consider making this a tuple-like type (i.e. a type you specialize `std::tuple_size` and `std::tuple_element` for, see case 2 here: std::tuple_size). This would allow you to use techniques similar to the one used in my answer here https://stackoverflow.com/a/73091984/2991525 to create a fold expression for accessing different types and it doesn't required the members to have the same type. – fabian Jul 24 '22 at 09:49

1 Answers1

2

Actually it's perfectly fine to read from a union member other than the one you have written too as long as you only access a common prefix. So

union {
    State st;
    struct {
        double x;
    };
} state;

state.st.x = 1;
if (state.x == 1) // perfectly fine.

The problem is that the rules for the layout of structs is complicated and a lot is implementation defined. The struct with 4 doubles could have padding between doubles for some reason and then your array of doubles wouldn't access the same bytes.

Unless the standard starts mandating the padding or describes when padding must be equal for unions to work like you ask this can't be allowed.


I recommend watching named tupples

Goswin von Brederlow
  • 11,875
  • 2
  • 24
  • 42