The sizeof an empty class or structure is 1

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Banfa
    Recognized Expert Expert
    • Feb 2006
    • 9067

    The sizeof an empty class or structure is 1

    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

    [code=cpp]T array[5];

    int diff = &array[3] - &array[2];

    // diff = 1
    [/code]

    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

    [code=cpp]
    &array[3] - &array[2] = &array[3] - &array[1]
    = &array[3] - &array[1]
    = &array[3] - &array[0]
    = 0
    [/code]

    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.
  • weaknessforcats
    Recognized Expert Expert
    • Mar 2007
    • 9214

    #2
    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.

    [code=cpp]
    class MyClass
    {
    public:
    void AMethod() {cout << "Hello" << endl;}
    };
    int main()
    {
    MyClass obj;
    MyClass* ptr = &obj;
    obj.AMethod();
    ptr->AMethod();
    cout << sizeof(obj) << endl; //displays 1
    }
    [/code]

    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.

    [code=cpp]
    class MyClass
    {
    public:
    virtual void AMethod() {cout << "Hello" << endl;}
    };
    int main()
    {
    MyClass obj;
    MyClass* ptr = &obj;
    obj.AMethod();
    ptr->AMethod();
    cout << sizeof(obj) << endl; //displays 4
    }
    [/code]

    Comment

    • Peterwkc
      New Member
      • Apr 2007
      • 55

      #3
      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.

      Comment

      • weaknessforcats
        Recognized Expert Expert
        • Mar 2007
        • 9214

        #4
        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.

        Comment

        • jyotis999
          New Member
          • Oct 2008
          • 1

          #5
          Originally posted by weaknessforcats
          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.

          [code=cpp]
          class MyClass
          {
          public:
          void AMethod() {cout << "Hello" << endl;}
          };
          int main()
          {
          MyClass obj;
          MyClass* ptr = &obj;
          obj.AMethod();
          ptr->AMethod();
          cout << sizeof(obj) << endl; //displays 1
          }
          [/code]

          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.

          [code=cpp]
          class MyClass
          {
          public:
          virtual void AMethod() {cout << "Hello" << endl;}
          };
          int main()
          {
          MyClass obj;
          MyClass* ptr = &obj;
          obj.AMethod();
          ptr->AMethod();
          cout << sizeof(obj) << endl; //displays 4
          }
          [/code]
          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.

          Comment

          • weaknessforcats
            Recognized Expert Expert
            • Mar 2007
            • 9214

            #6
            Originally posted by jyotis999
            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.

            Comment

            Working...