Pages

Saturday, June 20, 2015

cpp object size

If you have ever noticed that objects of empty classes have a non zearo size or variable reordering can change the size of the objects,
 you probably wanted to figureout whats going on! Guess what, you are at the right place :D if you know this, you can probably write space efficient code.
So what are the things that affect a size of a object? as you would guess size of the non static member variables. But thats not all there are two other things. They are,
 alignment requirements of those member variables and the alignment requirement of the struct or class (which depends on the alignment requirements of the member variables).
There are other things which are imposed by the langues. Those are order of the varibles, presence of virtual members and inheritance.

Size of empty objects
Now lets inspect what is the deal with non zearo size of the empty objects. The standard has the following.

Unless it is a bit-field (9.6), a most derived object shall have a non-zero size and shall occupy one or more bytes of storage.
Base class subobjects may have zero size. An object of trivially copyable or standard-layout type (3.9) shall occupy contiguous bytes of storage

Lets clarify what the above says with examples.

class A

{}; // size = 1



class B:public A

{}; // size =1;



class C

{   A a;  A b; }; // size = 2

Presence of virtual members
Now what happens when there are virtual functions? When virtual members are present each class that has them has virtual table and each instance of the of these classes contains a pointer to that table. Therefore the size would require the additional amout of pointer size irrespective of the number of virtual members. Here is an example.

class D

{   virtual void tt(){}; }; // size = 4



class E{ virtual void t1(){}; virtual void t2(){}; }; // size = 4

Alignment and Ordering of member variables
alignment requirements of data types are not enforced by the language rarther it is imposed by the processor architecture or OS. These requirements are
enforced for efficient data fetching from memory. The alignment requirement is influenced by the bus width. Processor can fetch a word in a single cycle,
that would be 4 bytes in a 32 bit machine. Alignments are enforced so that the processor can fetch data with minimum number of memory cycles. This would suggest
that alignment requirement of int would be 4 so that it would be stored in a single word rather than spread in two different words. Can you guess the alignment requirement
of a short type? it would be 2 otherwise if odd starting addresses were allowed it can spread to two different words requiring two memory cycles. What about a double?
"A double (eight bytes) will be 8-byte aligned on Windows and 4-byte aligned on Linux (8-byte with -malign-double compile time option)."
- http://en.wikipedia.org/wiki/Data_structure_alignment
You can try using google for the reason behind this type of differences :( similarly there are alignment requirements for structs as well. That is the alignment requirement of a
struct would be same as the alignment requirement of the member that has the largest requirement. That is if a struct has a int and a short alignment requirement of the struct would be
4(int has the largest alingment (4) in this struct ). This is needed to create array of struct because arrays elements occupy contigues memory without padding thus it could violate
alignments of memebers of the struct.
Having known these, now we can try to guess the size of different structs. Note that sizes and alignments of int = 4, short = 2, char = 1 in windows 32 bit machine. So lets go,

struct first{char a; int b;}; // size = 8

sizeof(char) + 3 byte padding (to aling int to multiple of 4) + sizeof(int)

struct first_c{int b; char a;}; // size = 8

sizeof(int) + sizeof(char) + 3 byte padding to make the size multipe of 4 (largest type is int)
This shows that reordering does not always improves the size.

struct second{char a; short b;}; // size = 4

sizeof(char) + 1 byte padding (to aling short to multiple of 2) + sizeof(short)

struct third{short a;int b;short c; int d;}; // size =16

sizeof(short) + 2 byte padding (to aling int to multiple of 4) + sizeof(int) + sizeof(short) + 2 byte padding (to aling int to multiple of 4)  + sizeof(int)

Well how to reorder the elements so that the size is minimized? arrange them in the decending order of their aligning requirements. This way only the padding at the end of the
struct would be added to match the requirements of the struct and we can avoid padding in between the members.

Now can't the compilers do it by themselves. The standard has things like following to restrict the comilers.

Nonstatic data members of a (non-union) class declared without an intervening access-specifier are allocated so that later members have higher addresses within a class object.
The order of allocation of nonstatic data members separated by an access-specifier is unspecified (11.1)"

So thats about it! C U :D