Nitesh
Nitesh

Reputation: 315

Practical use of Anonymous union in real world C++ programing

I know that we can access anonymous unions without creating it's object(without dot), but could anybody please explain,what is the use of anonymous unions in real world c++ programing?

Upvotes: 4

Views: 766

Answers (3)

I actually remembered a use case I came across a while back. You know bit-fields? The standard makes very little guarantees about their layout in memory. If you want to pack binary data into an integer of a specific size, you are usually better off doing bit-wise arithmetic yourself.

However, with unions and the common initial sequence guarantee, you can put all the boilerplate behind member access syntax. So your code will look like it's using a bit-field, but will in fact just be packing bits into a predictable memory location.

Here's a Live Example

#include <cstdint>
#include <type_traits>
#include <climits>
#include <iostream>

template<typename UInt, std::size_t Pos, std::size_t Width>
struct BitField {
    static_assert(std::is_integral<UInt>::value && std::is_unsigned<UInt>::value,
                  "To avoid UB, only unsigned integral type are supported");
    static_assert(Width > 0 && Pos < sizeof(UInt) * CHAR_BIT &&  Width < sizeof(UInt) * CHAR_BIT - Pos,
                  "Position and/or width cannot be supported");

    UInt mem;

    BitField& operator=(UInt val) {
        if((val & ((UInt(1) << Width) - 1)) == val) {
            mem &= ~(((UInt(1) << Width) - 1) << Pos);
            mem |= val << Pos;
        }
        // Should probably handle the error somehow
        return *this;
    }

    operator UInt() {
        return (mem >> Pos) & Width;
    }
};

struct MyColor {
    union {
        std::uint32_t raw;
        BitField<std::uint32_t, 0,  8> r;
        BitField<std::uint32_t, 8,  8> g;
        BitField<std::uint32_t, 16, 8> b;
    };
    MyColor() : raw(0) {}
};


int main() {
    MyColor c;
    c.r = 0xF;
    c.g = 0xA;
    c.b = 0xD;

    std::cout << std::hex << c.raw;
}

Upvotes: 2

geza
geza

Reputation: 29952

Here's a real-world example:

struct Point3D {
    union {
        struct {
            float x, y, z;
        };
        struct {
            float c[3];
        };
    };
};
Point3D p;

You can access p's x/y/z coordinates with p.x, p.y, p.z. This is convenient.

But sometimes you want to access point as a float[3] array. You can use p.c for that.

Note: Using this construct is Undefined Behavior by the standard. But, it works on all compilers I've met so far. So, if you want to use such a construct, be aware, that this may broke some day.

Upvotes: 4

Tobias Ribizel
Tobias Ribizel

Reputation: 5421

I have mostly used unions to store multiple different types of elements in the same contiguous storage without resorting to dynamic polymorphism. Thus, every element of my union is a struct describing the data for the corresponding node type. Using an anonymous union mostly gives a more convenient notation, i.e. instead of object.union_member.struct_member, I can just write object.struct_member, since there is no other member of that name anyways.

A recent example where I used them would be a rooted (mostly binary) tree which has different kinds of nodes:

struct multitree_node {
    multitree_node_type type;
    ...
    union {
        node_type_1 n1;
        node_type_2 n2;
        ...
    };
};

Using this type tag type I am able to determine which element of the union to use. All of the structs node_type_x have roughly the same size, which is why I used the union in the first place (no unused storage).

With C++17, you would be able to do this using std::variant, but for now, using anonymous unions are a convenient way of implementing such 'polymorphic' types without virtual functions.

Upvotes: 6

Related Questions