Ihor Shevchenko’s Post

💡 Understanding union vs std::variant in C++ (from low-level to modern safety) Let’s start with a classic C++ concept: union. A union allows multiple members to share the same memory location. Instead of allocating space for each field, it uses only enough memory for the largest one. union Value { Node* p; int i; }; Here: p and i occupy the same address The union size = max(sizeof(Node*), sizeof(int)) 👉 This is efficient — but comes with a cost. ⚠️ The Problem A union does not track which value is active. Value v; v.i = 42; // Later... std::cout << v.p; // ❌ Undefined behavior You’re responsible for remembering what’s stored. That’s why we often add a manual tag: enum class Type { ptr, num }; struct Entry { Type t; Value v; }; And use it like: if (entry.t == Type::num) std::cout << entry.v.i; This pattern is called a tagged union. 🧠 The Modern C++ Solution: std::variant C++ now gives us a safer, cleaner alternative: #include <variant> using Value = std::variant<Node*, int>; Now: The type knows what it currently holds No manual tag needed No undefined behavior (if used correctly) ✅ Accessing the value safely Value v = 42; if (std::holds_alternative<int>(v)) { std::cout << std::get<int>(v); } Or even better: std::visit([](auto&& val) { std::cout << val; }, v); In modern C++, the default choice should almost always be: 👉 std::variant over raw union #cpp #cplusplus #moderncpp #programming #softwareengineering #systemsprogramming #lowlevel #memorymanagement #cpp17 #developers

Another benefit to using std::variant is that it automatically handles lifetimes and RAII behavior for the value(s) it contains. A bare union may have less overhead in some cases, but a lot of resource management becomes manual again.

To view or add a comment, sign in

Explore content categories