Running the program:
Generates this output:
the size of A::c1: 1 the size of A::i1: 4 the size of A::c2: 1 the size of A::i2: 4 -- Total: 10 The size of A: 16
(Compiled by both Linux/GCC 4.9.2 and Visual Studio 2015, using x86 CPU)
The structure A occupies 6 bytes more than the sum of its members.
the mystery thickens when we check the output for structure B having the same elements in a slightly different order:
Now the output is:
the size of B::c1: 1 the size of B::i1: 4 the size of B::c2: 1 the size of B::i2: 4 -- Total: 10 The size of B: 12
Just moving c1 deceleration caused the B structure to shrink by 4 bytes! Yet it’s total size is still larger than the sum of it’s members.
why does it happen? The hardware is optimized to read data from memory address which are multiples of the data size : 4 bytes integers (int32) are read from addresses which are multiples of 4. Assuming the first address is 0 valid address for int32 would be 0, 4, 8, 12 .. 4n. 1 byte sized chars are read from addresses (0,1,2,3.. n) .
In an additional constraint , the C++ 11 standard requires that data members are allocated in memory in the same order they are declared, assuming they have the same access access-specifier (private, public protected).
It just happens that in our A,B structures, all the data members have public access specifier, causing the compiler to layout the member in the same order I defined them.
For simplicity lets assume memory start with address 0: When laying out an object instantiated from struct A, The compiler will start with address 0 allocating that byte for char member c1, It then must skip addresses 1,2,3 as they are not multiples of 4 and not suitable to store an int32 data type. So i1 get allocated addresses 4-7. Next, char member c2 is assigned address 8. The following 3 addresses are again skipped, and i2 is assigned address 12-15.
With 10 spaces occupied by actual members and 6 bytes “skipped” (the proper term is, padding) we get the 16 bytes as the size of structure A.
with Structure B we need only two padding bytes (after allocating space for c2) so it’s final size is 12 instead of 16:
Note: The developer can instruct the compiler to store the data members with no regard for alignment, however, it will cost heavily in performance since the CPU will need to shuffle the bytes around after reading them.
Empty classes and classes including virtual methods, are another examples where an object is larger than it appears to be at first glance:
Here the output is:
the size of A: 1 the size of B: 4
The size of structure A is 1 for no apparent reason, it has no data members, So where did this byte come from?
Let’s suppose we could have a class (let’s call it O) who’s size is zero, that is sizeof(O)=0 , In that case, I could have written this declaration :
the compiler will have to place o1 at the first available address – 0 and place o2 and o3 right after it. But the size of every O object is 0 so all objects o1,o2,o3 will all be allocated the same address – 0. However, different objects must have different addresses so zeor sized classes cannot be permitted and a class must have a minimal size of 1 byte.
what about the 3 extra bytes added to structure B once the Hi function became virtual?
In this case having a virtual function means including a pointer to the virtual function table aka vftable. The pointer is a hidden member of the object accounting for the 4 bytes.
The size and layout of C++ objects are not alway intuitive. Assuming the location of an individual data member from its supposed layout in memory is asking for a slow, agonizing decent into insanity. On the other hand, paying attention to alignment considerations is a way to pack your objects more tightly in memory. When you need every last byte.