C++ EBCO and [[no_unique_address]] | 'Empty Base Optimization' Complete Guide
이 글의 핵심
EBCO and C++20 [[no_unique_address]] solving the problem of empty classes occupying memory. From std::tuple, std::unique_ptr implementation secrets, memory layout optimization to practical patterns.
Introduction: “Why does empty class occupy 1 byte?"
"Why is std::unique_ptr<T, Deleter> 16 bytes instead of 8 bytes?”
In C++, empty class (Empty Class—class without member variables) also occupies minimum 1 byte. This is because each object must have unique address. But this rule causes wasted memory when having stateless functors or custom deleters as members.
EBCO (Empty Base Class Optimization) is a compiler optimization where inheriting empty class as base makes size 0. C++20’s [[no_unique_address]] attribute allows applying this optimization to member variables too.
What This Guide Covers:
- Empty class rule: Why it occupies 1 byte
- EBCO principle: Size 0 when inherited as base class
- [[no_unique_address]]: C++20 member variable optimization
- Practical usage: std::tuple, std::unique_ptr, compressed pair
- Problem scenarios: When memory layout optimization is needed
- Complete examples: Custom smart pointer, compressed pair implementation
- Common errors: EBCO failure cases, ABI compatibility
- Production patterns: Standard library implementation techniques
1. Empty Class Rule and EBCO
Why Empty Class Occupies 1 Byte
C++ standard requires all objects have unique address. Even empty class needs minimum 1 byte for each array element to have different address.
Below is an implementation example using C++. Define a class to encapsulate data and functionality. Understand the role of each part while examining the code.
struct Empty {};
int main() {
Empty e1, e2;
std::cout << sizeof(Empty) << '\n'; // 1
std::cout << &e1 << " vs " << &e2 << '\n'; // Different addresses
Empty arr[10];
std::cout << &arr[0] << " vs " << &arr[1] << '\n'; // 1 byte apart
}
Output:
1
0x7ffc1234 vs 0x7ffc1235
0x7ffc1240 vs 0x7ffc1241
Problem When Having as Member
Below is an implementation example using C++. Define a class to encapsulate data and functionality. Try running the code directly to check its operation.
struct Empty {};
struct Container {
int value; // 4 bytes
Empty empty; // 1 byte + 3 bytes padding (due to alignment)
// Total 8 bytes
};
static_assert(sizeof(Container) == 8);
Problem: Empty has no state but wastes 4 bytes (including padding).
EBCO: Size 0 When Inheriting as Base Class
EBCO (Empty Base Class Optimization) is compiler optimization making empty base class size 0.
Below is an implementation example using C++. Define a class to encapsulate data and functionality. Try running the code directly to check its operation.
// Type definition
struct Empty {};
struct Optimized : Empty {
int value; // 4 bytes
// Empty is size 0 → Total 4 bytes
};
static_assert(sizeof(Optimized) == 4);
Key: Base class is not array element so unique address rule is relaxed. Compiler places empty base at same address as derived class start to save space.
2. C++20 [[no_unique_address]]
Basic Usage
C++20 [[no_unique_address]] attribute allows applying EBCO to member variables.
struct Empty {};
struct Optimized {
int value; // 4 bytes
[[no_unique_address]] Empty empty; // 0 bytes
// Total 4 bytes
};
static_assert(sizeof(Optimized) == 4);
Comparison with EBCO
| Method | Syntax | Limitation |
|---|---|---|
| EBCO | Inherit as base | Inheritance required |
| [[no_unique_address]] | Member attribute | C++20 required |
Summary
Key Points
- Empty class: Occupies minimum 1 byte
- EBCO: Size 0 when inherited as base class
- [[no_unique_address]]: C++20 member optimization
- Use cases: Smart pointers, tuple, compressed pair
- Conditions: Empty type, no virtual functions
When to Use
✅ Use EBCO/[[no_unique_address]] when:
- Member is empty type
- Want to minimize memory
- Implementing smart pointers/containers
- Optimizing memory layout
❌ Don’t use when:
- Type has state
- Has virtual functions
- Adds unnecessary complexity
Best Practices
- ✅ Use for stateless functors
- ✅ Apply in custom smart pointers
- ✅ Use [[no_unique_address]] in C++20
- ❌ Don’t assume EBCO always applies
- ❌ Don’t forget ABI compatibility
Related Articles
- C++ Alignment and Padding
- C++ Cache and Data-Oriented Design
- C++ Pimpl
Master EBCO for memory-efficient C++ code! 🚀