The Prof and The Empty Class
BACK TO RECORDS

The Prof and The Empty Class

March 5, 2026C++ / C++ Internals / Memory Layout / Systems Programming / Programming Languages / Compiler Behavior
Why an Empty Class Has Size 1 Byte

During my bachelor's days, I spent a lot of time on Codeforces. I was obsessed with algorithms and competitive programming, solving problem after problem. Slowly I started getting good at it. My rating improved, and I began to feel like I truly understood C++ and algorithms. On Codeforces, I had become a Specialist and was now trying to push myself toward becoming an Expert.

Then COVID happened.

Classes moved online, and by the time college reopened, we were in the 4th semester. One of the subjects that semester was Design and Analysis of Algorithms. Because of my competitive programming background, I was often able to solve algorithmic questions quickly during class discussions. I started getting the spotlight — the guy who could crack algorithmic questions.

Somewhere in my head, I had started believing something dangerous:

Maybe I had already become the lord of C++.

Algorithm class discussion

Then my favourite professor, Sanjeet Kumar, asked a question that completely humbled me.

What is the size of an empty class in C++?

I froze.

I had solved countless algorithmic problems and written thousands of lines of C++, yet I couldn't answer this seemingly simple question.

Sir mentioned that the size is not zero because the compiler needs to keep track of objects. That answer satisfied the classroom.

But it didn’t satisfy me.

If an empty class has no data members, why should it occupy any space at all? Was the compiler simply reserving a byte arbitrarily, or was there a deeper reason hidden inside the C++ memory model?

So let's explore the real reason.

1. Why an Empty Class Has Size 1 Byte

In C++, every object must have a unique address in memory.

Consider this class:

class Empty {};

int main() {
    Empty a;
    Empty b;

    std::cout << &a << std::endl;
    std::cout << &b << std::endl;
}

If sizeof(Empty) were 0, then a and b would occupy no space.

That would cause:

&a == &b

Both objects would have the same address, which violates a fundamental rule:

Two distinct objects must have different memory addresses.

So the compiler gives the class 1 byte, just enough so objects can occupy different locations.

#include <iostream>

class Empty {};

int main() {
    std::cout << sizeof(Empty) << std::endl;
}
Output:

1

2. What Would Happen If It Were 0 Bytes

Let’s imagine C++ allowed this.

Hypothetical scenario

class Empty {};

int main() {
    Empty a;
    Empty b;

    if (&a == &b)
        std::cout << "Same address!";
}

If sizeof(Empty) == 0, memory layout would look like:

Stack

|------|
|  a   |
|------|
|  b   |
|------|

But both would start at the same location because they take 0 space.

So:

&a == &b
Output:

Same address!

Now the compiler cannot distinguish objects.

3. Even Worse Problem (Arrays)

Consider:

Empty arr[10];

Array layout normally:

arr[i] = base + i * sizeof(T)

If sizeof(T) = 0:

arr[i] = base + i * 0

So:

&arr[0] == &arr[1] == &arr[2] ...

All elements point to the same address.

Arrays become meaningless.

4. Demonstrating Address Difference (Real C++)

#include <iostream>
using namespace std;

class Empty {};

int main() {
    Empty a, b;

    cout << "Size of Empty: " << sizeof(Empty) << endl;
    cout << "Address of a: " << &a << endl;
    cout << "Address of b: " << &b << endl;
}
Example output:

Size of Empty: 1
Address of a: 0x7ffd3c1a7b4e
Address of b: 0x7ffd3c1a7b4f

Notice:

difference = 1 byte

5. Special Case: Empty Base Optimization (EBO)

C++ has a clever trick.

If an empty class is used as a base class, the compiler may not allocate that 1 byte.

Example:

#include <iostream>

class Empty {};

class Derived : public Empty {
    int x;
};

int main() {
    std::cout << sizeof(Derived) << std::endl;
}
Output:

4

Not:

5

Because the compiler applies Empty Base Optimization (EBO).

6. The Rule From the C++ Standard

C++ ensures:

sizeof(object) >= 1

So every object occupies at least 1 byte.

This guarantees:

  1. Unique addresses
  2. Correct pointer arithmetic
  3. Valid arrays
  4. Correct object identity
Systems Programming Insight

This tiny 1 byte rule is what keeps:

  1. object identity
  2. pointer arithmetic
  3. array indexing
  4. polymorphism

consistent across the entire C++ memory model.

Even something as “empty” as a class must exist physically in memory.

Since the C++ standard forbids sizeof(class) = 0, we cannot truly create a zero-size class. But we can simulate what would happen if the compiler allowed it. The goal is to demonstrate the catastrophic consequences.

We’ll simulate it by forcing all objects to share the same memory location, which mimics a zero-byte object.

7.Simulation Idea

If an object had size 0, then:

address(object[i]) = base + i * 0

So all objects would have the same address.

We simulate this by making every object return the same address.

8. Simulated Zero-Size Class

#include <iostream>
using namespace std;

class ZeroSizeSim {
public:
    static char dummy;

    void* operator&() {
        return &dummy;   // force same address
    }
};

char ZeroSizeSim::dummy;

int main() {
    ZeroSizeSim a, b, c;

    cout << "Address of a: " << &a << endl;
    cout << "Address of b: " << &b << endl;
    cout << "Address of c: " << &c << endl;

    if (&a == &b && &b == &c)
        cout << "All objects share the same address (simulating size 0)" << endl;
}
Output

Address of a: 0x5642...
Address of b: 0x5642...
Address of c: 0x5642...
All objects share the same address

Now we have effectively simulated a zero-byte class.

9. Now Watch Arrays Break

#include <iostream>
using namespace std;

class ZeroSizeSim {
public:
    static char dummy;

    void* operator&() {
        return &dummy;
    }
};

char ZeroSizeSim::dummy;

int main() {
    ZeroSizeSim arr[5];

    for(int i=0;i<5;i++)
        cout << "&arr[" << i << "] = " << &arr[i] << endl;
}
Output

&arr[0] = 0x55...
&arr[1] = 0x55...
&arr[2] = 0x55...
&arr[3] = 0x55...
&arr[4] = 0x55...

All elements have identical addresses.

So:

arr[0] == arr[4]

Arrays become meaningless.

10. Pointer Arithmetic Breaks

Normal pointer arithmetic:

ptr + i = base + i * sizeof(T)

If sizeof(T)=0:

ptr + i = base

Example simulation:

#include <iostream>
using namespace std;

int main() {

    char base;

    char* ptr = &base;

    for(int i=0;i<5;i++)
        cout << (void*)(ptr + i*0) << endl;
}
Output:

0x7ffd...
0x7ffd...
0x7ffd...
0x7ffd...
0x7ffd...

Pointer movement does not move.

11. Memory Model Collapse

Feature Problem
Object identity two objects same address
Arrays all elements same location
Pointer arithmetic impossible
STL containers broken
new[] allocation undefined

So C++ enforces:

sizeof(T) >= 1

12. Deep Compiler Insight

The 1 byte is not for data.

It is a placeholder for object identity.

This tiny byte ensures:

&a != &b

which is essential for the entire C++ object model.

Final Insight

C++ enforces the rule:

sizeof(T) >= 1

This tiny rule protects the entire object model.

The byte is not for data. It is a placeholder ensuring object identity exists in memory.

In C++, even emptiness must occupy space — because identity in memory is the foundation on which every abstraction stands.