Is reading inactive union member of the same type as active one well-defined?

520 views Asked by At

Consider the following structure:

struct vec4
{
    union{float x; float r; float s};
    union{float y; float g; float t};
    union{float z; float b; float p};
    union{float w; float a; float q};
};

Something like this seems to be used in e.g. GLM to provide GLSL-like types like vec4, vec2 etc..

But although the intended usage is like to make this possible

vec4 a(1,2,4,7);
a.x=7;
a.b=a.r;

, it seems to be an undefined behavior, because, as quoted here,

In a union, at most one of the data members can be active at any time, that is, the value of at most one of the data members can be stored in a union at any time.

Wouldn't it be better to e.g. use just define the structure something like the following?

struct vec4
{
    float x,y,z,w;
    float &r,&g,&b,&a;
    float &s,&t,&p,&q;
    vec4(float X,float Y,float Z,float W)
        :x(X),y(Y),z(Z),w(W),
         r(x),g(y),b(z),a(w),
         s(x),t(y),p(z),q(w)
    {}
    vec4()
        :r(x),g(y),b(z),a(w),
         s(x),t(y),p(z),q(w)
    {}
    vec4(const vec4& rhs)
        :x(rhs.x),y(rhs.y),z(rhs.z),w(rhs.w),
         r(x),g(y),b(z),a(w),
         s(x),t(y),p(z),q(w)
    {}
    vec4& operator=(const vec4& rhs)
    {
        x=rhs.x;
        y=rhs.y;
        z=rhs.z;
        w=rhs.w;
        return *this;
    }
};

Or am I working around a non-existent issue? Is there maybe some special statement allowing access to identically-typed inactive union members?

1

There are 1 answers

0
AudioBubble On

I think the quote in which you are referring to is directed at having different types with in the union.

struct foo {
  union {
    float x,
    int y,
    double z,
  };
};

These are different data, conveniently stored into the same structure, unions are not supposed to be a casting mechanism.

GLM approach uses the same data and uses the union for an alias mechanic.

Your approach might be 'better' C++ but its worse 'Engineering'. Vector math needs to be fast, and the smaller the better in this case.

Your implementation is makes the vector 3 times bigger. sizeof(glm::vec4); // 16 while sizeof(your_vec4); // 48 - ouch If you where processing a large armount of these which is often the case, 3 times as more cache misses with your_vec4.

I think you are right though glm's use of unions as alias's is a bit much, while I'm not sure if its undefined, but this type of thing I've seen a lot without much issue, and glm is widely used.

I don't really see the need to emulate glsl in C++, and struct { float x,y,z,w; } would be better (at least in my mind).