422,751 Members | 2,100 Online
Bytes IT Community
Submit an Article
Got Smarts?
Share your bits of IT knowledge by writing an article on Bytes.

The sizeof an empty class or structure is 1

Banfa
Expert Mod 5K+
P: 8,916
I thought I would write a little article about this because it is regularly asked as a question in the Forums.

Firstly this is a C++ issue, it is strictly against the rules of C to create a class with no members. This makes sense because the only real use for a structure or class with no data members and virtual functions is as the base from which to derive other classes and structures or as a container for non-virtual methods.

The reason this happens boils down to properly implementing the standard, one of the things the C++ standard says is that "no object shall have the same address in memory as any other variable". There is a very good reason for this, take an array of type T then subtracting the pointer to 1 entry in the array from another should give the difference in indexes

Expand|Select|Wrap|Line Numbers
  1. T array[5];
  2.  
  3. int diff = &array[3] - &array[2];
  4.  
  5. // diff = 1
  6.  
This is actually pointer arithmetic, we have taken 2 pointers and found their difference. The compiler performs this calculation using a formula equivalent to this

diff = ((char *)&array[3] - (char *)&array[2]) / sizeof T;

This is just an example, but this type of calculation reliant on the sizeof T occurs in all sorts of pointer arithmetic.

If objects were allowed to have the same address because their type was 0 sized then this calculation would not be possible because

Expand|Select|Wrap|Line Numbers
  1. &array[3] - &array[2] = &array[3] - &array[1]
  2.                       = &array[3] - &array[1]
  3.                       = &array[3] - &array[0]
  4.                       = 0
  5.  
It is not possible to distinguish the different objects in pointer arithmetic.

Additionally there is the problem that the compiler had to divided by sizeof T, which would be a divide by zero error, although this could be coded round.

Allowing objects to have the same memory address would result in the need to implement some rather complex code to handle pointer arithmetic on them.

So objects must not have the same memory address, that is they must be individually addressable. What is the easiest way to ensure this? Make sure that all types have a non-zero size. In order to achieve this the compiler adds a dummy byte to structures and classes that have no data members and no virtual functions so that they have a size of 1 rather than a size of 0 and then they are guaranteed to have a unique memory address.
Jun 11 '07 #1
Share this Article
Share on Google+
5 Comments


weaknessforcats
Expert Mod 5K+
P: 9,132
A class (or struct) can have member functions without using any data members. Unless you can create an object of this class, you can't call the methods. For this reason, a class (or struct) that has no data members is created with a sizeof 1 byte.

This also allows you to define a pointer to an object of that class. You can't define a pointer of you cannot acquire the address of an object of the pointer type. One byte is the smallest addressable memory unit. The only time in C++ when you cannot create an object of the class is when it contains (or has inherited) a pure virtual function.

Expand|Select|Wrap|Line Numbers
  1. class MyClass
  2. {
  3.     public:
  4.        void AMethod() {cout << "Hello" << endl;}
  5. };
  6. int main()
  7. {
  8.     MyClass obj;
  9.     MyClass* ptr = &obj;
  10.     obj.AMethod();
  11.     ptr->AMethod();
  12.     cout << sizeof(obj) << endl;    //displays 1
  13. }
  14.  
When a class contains no data variables but does have at least one virtual function, the object is created containing the address of the virtual funciton table (VTBL) as part of the object. Because of this, the size of the object will now be 4.

Expand|Select|Wrap|Line Numbers
  1. class MyClass
  2. {
  3.     public:
  4.        virtual void AMethod() {cout << "Hello" << endl;}
  5. };
  6. int main()
  7. {
  8.     MyClass obj;
  9.     MyClass* ptr = &obj;
  10.     obj.AMethod();
  11.     ptr->AMethod();
  12.     cout << sizeof(obj) << endl;    //displays 4
  13. }
  14.  
Dec 10 '07 #2

P: 55
I don't understand about the statement.

Its space overhead is one pointer in each object of a class with a virtual function plus one vtbl for each such class.

Please clear my doubt.

Thanks.
Mar 2 '08 #3

weaknessforcats
Expert Mod 5K+
P: 9,132
I think you almost understand this.

There is one VTBL for all objects of a class with virtual functions.

Each object of the class has a pointer to that VTBL. Therefore, the overhead in each object is one pointer.
Mar 4 '08 #4

P: 1
A class (or struct) can have member functions without using any data members. Unless you can create an object of this class, you can't call the methods. For this reason, a class (or struct) that has no data members is created with a sizeof 1 byte.

This also allows you to define a pointer to an object of that class. You can't define a pointer of you cannot acquire the address of an object of the pointer type. One byte is the smallest addressable memory unit. The only time in C++ when you cannot create an object of the class is when it contains (or has inherited) a pure virtual function.

Expand|Select|Wrap|Line Numbers
  1. class MyClass
  2. {
  3.     public:
  4.        void AMethod() {cout << "Hello" << endl;}
  5. };
  6. int main()
  7. {
  8.     MyClass obj;
  9.     MyClass* ptr = &obj;
  10.     obj.AMethod();
  11.     ptr->AMethod();
  12.     cout << sizeof(obj) << endl;    //displays 1
  13. }
  14.  
When a class contains no data variables but does have at least one virtual function, the object is created containing the address of the virtual funciton table (VTBL) as part of the object. Because of this, the size of the object will now be 4.

Expand|Select|Wrap|Line Numbers
  1. class MyClass
  2. {
  3.     public:
  4.        virtual void AMethod() {cout << "Hello" << endl;}
  5. };
  6. int main()
  7. {
  8.     MyClass obj;
  9.     MyClass* ptr = &obj;
  10.     obj.AMethod();
  11.     ptr->AMethod();
  12.     cout << sizeof(obj) << endl;    //displays 4
  13. }
  14.  
I understood that in case of virtual functions the size of the object is increasing by the VPtr (virtual pointer) which is pointing to base address of VTBLE, but please explain why it's 4 bytes exactly? why not some other value.
Oct 1 '08 #5

weaknessforcats
Expert Mod 5K+
P: 9,132
I understood that in case of virtual functions the size of the object is increasing by the VPtr (virtual pointer) which is pointing to base address of VTBLE, but please explain why it's 4 bytes exactly? why not some other value.
It's the sizeof a memory address in a 32-bit operating system.
Oct 4 '08 #6