A lot of students have trouble comprehending why we would employ a structure that “forgets” old data when a new member is added. This article will explain how C++ unions work, provide you with real-world examples, and go over advanced topics like tagged unions to help you build better, more efficient code.
What are C++ Unions?
A union is a type of data that the user defines, just like a class or struct. The main distinction, though, is how they use memory. In a struct, each member has its own address. In this case, all members have the same memory address.
Key Features of Unions
- Size: The biggest member of a union decides how big it is.
- Memory Sharing: At any given time, only one member can hold a value.
- Efficiency: They help you save space when you have a variable that has to hold several kinds of data, but not at the same time.
How to Declare C++ Unions?
To create a union, you use the union keyword. The syntax looks remarkably like a struct, but the behaviour under the hood is entirely different.
C++
union Data Holder {
int intValue;
float floatValue;
char charValue;
};
In this example, if an integer takes 4 bytes, a float takes 4 bytes, and a char takes 1 byte, the total size of the Data Holder union will be 4 bytes. If this were a struct, it would take at least 9 bytes.
Also Read:
- C++ Syntax: Tutorials For Beginners
- Top 10 Reasons To Learn C++
- C Plus Plus Programming Language Explained
- Top Features of C++ Programming Language
- C++ Programming: An Introduction
- Addition Program In C++: Analogy-Based Examples
How to Access C++ Unions Members?
In this, all members share the same memory. This means:
Only the last assigned member should be accessed
If you assign a value to one member and then read another member, the result will be incorrect or garbage.
Example:
union Data {
int x;
float y;
};
Data d;
d.x = 10;
cout << d.x; // Correct
d.y = 5.5;
cout << d.x; // Incorrect (garbage value)
This happens because assigning y overwrites the memory previously used by x.
How to Initialise C++ Unions?
You can also initialise a union at the time of declaration. However, only one member can be initialised.
Example:
union Data {
int x;
float y;
};
Data d = {10}; // Initializes only ‘x’
Important points:
- Only the first member is initialised by default
- You cannot initialise multiple members at once
Difference Between Unions and Structs
To truly grasp the value of unions in C++, we must look at how they sit in your computer’s RAM.
| Feature | Struct | Union |
| Memory Keyword | struct | union |
| Allocation | Sum of all members (plus padding) | Size of the largest member |
| Access | All members can be accessed at once | Only one member is active at a time |
| Storage | Every member has a unique location | All members share the same location |
C++ Unions Examples
Let’s look at a practical scenario. Imagine you are writing a program for a sensor that either returns a whole number (integer) or a precise decimal (float).
C++
#include <iostream>
using namespace std;
union SensorData {
int basicReading;
float precisionReading;
};
int main() {
SensorData mySensor;
mySensor.basicReading = 10;
cout << “Basic: ” << mySensor.basicReading << endl;
mySensor.precisionReading = 25.5;
// Now basicReading is corrupted because precisionReading took over the memory
cout << “Precision: ” << mySensor.precisionReading << endl;
return 0;
}
In the examples above, assigning a value to precisionReading overwrites the space previously used by basicReading. If you try to print basic reading after setting the float, you will get a “garbage” value.
What is a C++ Anonymous Union?
These are particularly useful when nested inside a struct. An anonymous union allows you to access its members directly without using the dot operator on the union name itself.
Rules for Anonymous Unions:
- They can’t have functions for members.
- They can’t have members that are private or protected.
- They must be defined within a scope (like a function or another struct).
Example of anonymous union:
C++
struct Employee {
char* name;
union {
int id_number;
char* id_string;
}; // No name given to this union
};
In this case, you can access emp.id_number directly, which keeps the code clean while still saving memory.
C++ Discriminated Unions
One of the biggest risks with a standard union is that the compiler doesn’t track which member is currently “active”. If you store a float but try to read an integer, your program won’t crash, but the data will be nonsensical.
To fix this, programmers utilise C++ tagged unions, which are also known as C++ discriminated unions. This means putting the union inside a struct and adding an enum “tag” that keeps track of what’s within the union.
How to Implement C++ Discriminated Unions?
C++
enum DataType { IS_INT, IS_FLOAT, IS_CHAR };
struct SafeUnion {
DataType type; // The “Tag” or “Discriminant”
union {
int i;
float f;
char c;
} data;
};
void printValue(SafeUnion su) {
if (su.type == IS_INT) cout << su.data.i;
else if (su.type == IS_FLOAT) cout << su.data.f;
else if (su.type == IS_CHAR) cout << su.data.c;
}
By using tagged unions, you gain the memory benefits of a union while maintaining the type safety of a more complex object. This is a common pattern in compiler design and protocol parsing.
Uses of C++ Unions in Programming
While modern computers have plenty of RAM, they remain relevant in several specific fields:
- Embedded Systems: When working with microcontrollers that have only a few kilobytes of memory, every byte counts.
- Network Protocols: Unions are great for parsing packets where a header might define different types of following data.
- Performance Optimisation: Reducing the memory footprint of a large array of objects can lead to better cache performance.
- Hardware Interfacing: Directly mapping memory-mapped I/O registers often requires the flexibility of unions.
Limitations of C++ Unions
Despite their power, unions come with strict rules in C++:
- No Inheritance: You cannot inherit from a union, nor can a union be a base class.
- Constructor Restrictions: You generally cannot have members with non-trivial constructors (like std::string) in a union unless you manage the construction and destruction manually.
Single Value: Remember that a union is not a container for multiple values; it is a single container that can change its “shape”.
FAQs
What is the primary advantage of using unions in C++?
The main advantage is memory efficiency. By allowing multiple members to share the same memory space, the total size is only as large as the biggest member, which is ideal for memory-constrained environments.
Can I use a string inside a union?
Generally, you should avoid using complex types like std::string because they have constructors and destructors. Unions do not know which member is active, so they won't know when to call the string's destructor, potentially leading to memory leaks.
How does a C++ anonymous union differ from a named one?
It does not have a name, and its members can be accessed directly in the containing scope without the dot operator. This is often used inside structs to simplify data access.
Why are C++ tagged unions safer than regular unions?
Also known as C++ discriminated unions, they include a separate variable (usually an enum) that tracks which member currently holds a valid value. This prevents the programmer from accidentally reading the wrong data type.
How do I find the size of a union?
You can use the sizeof() operator. This will return the size of the largest data member plus any necessary padding required by the system architecture.
