0
0
C++programming~15 mins

Union basics in C++ - Deep Dive

Choose your learning style9 modes available
Overview - Union basics
What is it?
A union in C++ is a special data type that allows storing different data types in the same memory location. It can hold only one of its member variables at a time, sharing the same space for all members. This means the size of the union is equal to the size of its largest member. Unions are useful when you want to save memory by reusing the same space for different types of data.
Why it matters
Unions exist to save memory when you need to store different types of data but never at the same time. Without unions, you would have to allocate separate memory for each type, wasting space. This is important in systems with limited memory, like embedded devices or performance-critical applications. Without unions, programs could be less efficient and use more memory than necessary.
Where it fits
Before learning unions, you should understand basic C++ data types, variables, and structs. After unions, you can learn about advanced memory management, type punning, and variant types like std::variant in modern C++. Unions fit into the journey of understanding how memory is organized and optimized in C++.
Mental Model
Core Idea
A union is like a single box that can hold different items, but only one item at a time, sharing the same space for all possible contents.
Think of it like...
Imagine a single drawer in a desk where you can keep either your pens, your notebooks, or your phone, but never all at once. The drawer's size is fixed, so it must be big enough for the largest item you want to store.
┌───────────────┐
│    Union      │
│───────────────│
│ Member A      │
│ (shares space)│
│───────────────│
│ Member B      │
│ (shares space)│
│───────────────│
│ Member C      │
│ (shares space)│
└───────────────┘

All members overlap in the same memory area.
Build-Up - 7 Steps
1
FoundationWhat is a Union in C++
🤔
Concept: Introduce the basic idea of a union and how it differs from a struct.
In C++, a union is declared like a struct but all members share the same memory location. For example: union Data { int i; float f; char c; }; Here, i, f, and c all use the same memory space. Only one can hold a meaningful value at a time.
Result
The union Data can store an int, float, or char, but only one at a time, sharing the same memory.
Understanding that union members overlap in memory is key to knowing how unions save space compared to structs.
2
FoundationMemory Size of a Union
🤔
Concept: Explain how the size of a union is determined by its largest member.
The size of a union is equal to the size of its largest member. For example, if int is 4 bytes, float is 4 bytes, and char is 1 byte, the union size will be 4 bytes. This is because all members share the same memory space, so the union must be big enough to hold the biggest member.
Result
The union Data from before will have a size of 4 bytes, enough to hold int or float.
Knowing that union size depends on the largest member helps predict memory usage and avoid surprises.
3
IntermediateAccessing Union Members Safely
🤔Before reading on: do you think you can read from any union member at any time safely? Commit to your answer.
Concept: Explain that only the last written member of a union holds a valid value and reading others is unsafe.
When you write to one member of a union, only that member's value is valid. Reading from a different member without writing to it first leads to undefined behavior. Example: Data d; d.i = 10; // valid float x = d.f; // unsafe, undefined behavior You must keep track of which member is active.
Result
Accessing the wrong member can cause unexpected results or program errors.
Understanding that unions do not track active members prevents bugs and undefined behavior.
4
IntermediateUsing Unions with Structs for Type Tagging
🤔Before reading on: do you think unions alone can safely store multiple types without extra information? Commit to your answer.
Concept: Introduce the pattern of combining a union with a type tag to know which member is active.
To safely use unions for multiple types, programmers often add a separate variable (called a tag) to remember which member is currently stored. Example: struct Variant { enum Type { INT, FLOAT, CHAR } type; union { int i; float f; char c; } data; }; This way, you check 'type' before accessing 'data'.
Result
This pattern avoids unsafe access and makes unions practical for storing different types.
Knowing how to combine unions with tags is essential for safe and effective use in real programs.
5
IntermediateAnonymous Unions for Convenience
🤔
Concept: Explain how anonymous unions allow direct access to members without naming the union.
C++ allows anonymous unions inside structs or classes. This means you can access union members directly without specifying the union name. Example: struct Example { union { int i; float f; }; // anonymous union }; Example e; e.i = 5; // direct access This makes code cleaner but still shares memory.
Result
Anonymous unions simplify syntax while keeping union behavior.
Understanding anonymous unions helps write cleaner code without losing union benefits.
6
AdvancedUnions and Type Punning
🤔Before reading on: do you think reading a different union member than the one written is always safe in C++? Commit to your answer.
Concept: Discuss how unions can be used for type punning but with caution due to undefined behavior rules.
Type punning means interpreting the same memory as different types. Unions are sometimes used for this, e.g., writing to an int member and reading from a float member. Example: union U { int i; float f; }; U u; u.i = 0x3f800000; // bit pattern for float 1.0 float x = u.f; // reads as float However, this is undefined behavior in strict C++ standards, though many compilers support it as an extension.
Result
Using unions for type punning can work but is not guaranteed portable or safe.
Knowing the risks of type punning with unions helps avoid subtle bugs and portability issues.
7
ExpertUnions in Modern C++ with std::variant
🤔Before reading on: do you think unions are the best way to store multiple types safely in modern C++? Commit to your answer.
Concept: Explain how std::variant improves on unions by providing type safety and automatic tracking of active member.
Modern C++ offers std::variant, a type-safe union alternative. It stores one of several types and keeps track of which is active. Example: std::variant v; v = 10; // stores int v = 'a'; // stores char std::variant prevents unsafe access and undefined behavior by design, unlike raw unions.
Result
std::variant is safer and easier to use than unions for multiple types in modern C++.
Understanding std::variant shows how language evolution addresses union limitations and improves safety.
Under the Hood
A union allocates a single memory block sized to fit its largest member. All members share this block starting at the same address. When you write to one member, the bits in that memory block represent that member's value. Reading a different member interprets the same bits differently, which can cause undefined behavior if not managed carefully.
Why designed this way?
Unions were designed to save memory by overlapping storage for different types, useful in low-level programming and embedded systems. The tradeoff is that the programmer must manage which member is active, as the language does not track this automatically. Alternatives like structs allocate separate memory for each member, which is safer but uses more space.
┌─────────────────────────────┐
│          Union Memory        │
│ ┌───────────────┐           │
│ │ Member A      │           │
│ │ (int, 4 bytes)│           │
│ ├───────────────┤           │
│ │ Member B      │           │
│ │ (float, 4 b)  │  <-- same │
│ ├───────────────┤  memory   │
│ │ Member C      │           │
│ │ (char, 1 byte)│           │
│ └───────────────┘           │
└─────────────────────────────┘

All members overlap in the same memory space.
Myth Busters - 4 Common Misconceptions
Quick: Can you safely read any union member regardless of which was last written? Commit to yes or no.
Common Belief:You can read any member of a union at any time without problems.
Tap to reveal reality
Reality:Only the last written member holds a valid value; reading others causes undefined behavior.
Why it matters:Ignoring this leads to bugs, crashes, or corrupted data in programs.
Quick: Does a union always use the combined size of all its members? Commit to yes or no.
Common Belief:A union's size is the sum of all its members' sizes.
Tap to reveal reality
Reality:A union's size equals the size of its largest member, not the sum.
Why it matters:Misunderstanding this causes wrong memory allocation and potential data corruption.
Quick: Is using unions for type punning guaranteed safe and portable in C++? Commit to yes or no.
Common Belief:Using unions to reinterpret data types is always safe and portable.
Tap to reveal reality
Reality:Type punning with unions is undefined behavior in standard C++, though some compilers allow it.
Why it matters:Relying on this can cause subtle bugs and non-portable code.
Quick: Are unions obsolete in modern C++ because of std::variant? Commit to yes or no.
Common Belief:Unions are outdated and should never be used in modern C++.
Tap to reveal reality
Reality:Unions are still useful for low-level memory control and performance-critical code, while std::variant is better for type safety.
Why it matters:Ignoring unions limits understanding of memory and low-level programming techniques.
Expert Zone
1
Unions do not call constructors or destructors of non-trivial types automatically, requiring manual management.
2
Using unions with non-POD (Plain Old Data) types requires placement new and explicit destruction to avoid undefined behavior.
3
Compiler-specific extensions sometimes allow safer type punning with unions, but relying on them reduces portability.
When NOT to use
Avoid unions when you need automatic type safety, constructors/destructors, or complex types. Use std::variant or polymorphism instead for safer and clearer code.
Production Patterns
Unions are used in embedded systems for memory efficiency, in network protocol parsing to interpret data packets, and in performance-critical code where manual memory control is essential.
Connections
std::variant
Builds-on
Understanding unions helps grasp how std::variant manages multiple types safely by tracking the active member.
Memory Management
Same pattern
Unions illustrate manual memory sharing, a core idea in memory management and optimization.
Electrical Switches
Analogy
Like a switch that connects one circuit at a time, a union connects one data type at a time to the same memory, showing how hardware concepts relate to software memory design.
Common Pitfalls
#1Reading from a union member different from the last written one.
Wrong approach:union Data { int i; float f; } d; d.i = 42; float x = d.f; // unsafe read
Correct approach:union Data { int i; float f; } d; d.i = 42; // Only read d.i here, not d.f
Root cause:Misunderstanding that union members share memory and only the last written member is valid.
#2Assuming union size is sum of all members.
Wrong approach:union U { char c; int i; }; // Assuming sizeof(U) == sizeof(char) + sizeof(int)
Correct approach:union U { char c; int i; }; // sizeof(U) == sizeof(int), the largest member
Root cause:Confusing union memory layout with struct layout.
#3Using unions with non-trivial types without proper construction/destruction.
Wrong approach:union U { std::string s; int i; }; U u; u.s = "hello"; // no constructor called explicitly
Correct approach:union U { std::string s; int i; }; U u; new (&u.s) std::string("hello"); // placement new // call destructor manually when done
Root cause:Not knowing unions don't automatically manage complex types.
Key Takeaways
A union stores different data types in the same memory space but only one at a time.
The size of a union equals its largest member's size, not the sum of all members.
Only the last written member of a union holds a valid value; reading others is unsafe.
Unions save memory but require careful management of which member is active.
Modern C++ offers std::variant for safer, type-tracked alternatives to unions.