sizeof class with int , function, virtual function in C++?
Asked Answered
S

5

24

This is an online C++ test question, which has been done.

#include<iostream>
using namespace std; 
class A
{

};
class B
{
int i; 
}; 

class C
{
void foo();
};
class D
{
virtual void foo();
};

class E
{
int i ; 
    virtual void foo();
};
class F
{
int i; 
    void foo();
};
class G
{
    void foo();
    int i;
    void foo1();
};

class H
{
    int i ;
    virtual void foo();
    virtual void foo1();
};
int main()
{
cout <<"sizeof(class A) : " << sizeof(A) << endl ;
cout <<"sizeof(class B) adding the member int i : " << sizeof(B) << endl ;
cout <<"sizeof(class C) adding the member void foo() : " << sizeof(C) << endl ;
cout <<"sizeof(class D) after making foo virtual : " << sizeof(D) << endl ;
cout <<"sizeof(class E) after adding foo virtual , int : " << sizeof(E) << endl ;
cout <<"sizeof(class F) after adding foo  , int : " << sizeof(F) << endl ;
cout <<"sizeof(class G) after adding foo  , int : " << sizeof(G) << endl ;
G g;
cout <<"sizeof(class G) after adding foo  , int : " << sizeof(g) << endl ;
cout <<"sizeof(class H) after adding int 2 virtual " << sizeof(H) << endl ;
return 0; 
}

output:

sizeof(class A) : 1
sizeof(class B) adding the member int i : 4
sizeof(class C) adding the member void foo() : 1
sizeof(class D) after making foo virtual : 8
sizeof(class E) after adding foo virtual , int : 16
sizeof(class F) after adding foo  , int : 4
sizeof(class G) after adding foo   , unsigned int : 4
sizeof(class g) after adding foo  , unsigned int : 4
sizeof(class H) after adding int 2 virtual 16

My questions:

Why siszeof(A) is 1 and sizeof(C) is 1 too ?

Why siszeof(H) is 16 but sizeof(G) is 4 ?

Why siszeof(E) is 16 but sizeof(F) is 4 ?

Why siszeof(D) is 8 but sizeof(E) is 16 ?

My guess:

A virtual function is a pointer with 8 bytes. But, I do not know why E size is 16 ? Adding a function to an empty class does not change its size ?

Any help is appreciated.

thanks

Swineherd answered 24/2, 2012 at 22:59 Comment(3)
The compiler is free to align members as it sees fit.Lease
This feels a lot like a homework question. Is it?Valenciavalenciennes
A few months ago, you posted an avalanche of copy-pasted interview questions and showed no interest in actually following up, or community interaction, or taking some time out and think and learn for yourself. Now you're back to doing the exact same thing again. This is not a tutorial website, and you will have to do some down-and-dirty learning yourself. Furthermore, search this site before posting, as many of the topics you (will) bring up have been discussed over and over on SO already.Clothes
C
50

First off, a virtual function is not a pointer with 8 bytes. In C++ nothing but sizeof(char) is guaranteed to be any number of bytes.

Second, only the first virtual function in a class increases its size (compiler-dependent, but on most - if not all - it's like this). All subsequent methods do not. Non-virtual functions do not affect the class's size.

This happens because a class instance doesn't hold pointers to methods themselves, but to a virtual function table, which is one per class.

So if you had:

class A
{
   virtual void foo();
}

and

class B
{
   virtual void goo();
   virtual void test();
   static void m();
   void x();
}

you would have sizeof(A) == sizeof(B).

And now:

Why siszeof(A) is 1 and sizeof(C) is 1 too ?

A and C have size 1 just because it's not allowed for a class to be of size 0. The functions have nothing to do with it. It's just a dummy byte.

Why siszeof(H) is 16 but sizeof(G) is 4 ?

G has only one member that accounts for memory - the int. And on your platform, sizeof(int) == 4. H, besides the int, also has a pointer to the vftable (virtual function table, see above). The size of this, size of int and allignment are compiler specific.

Why siszeof(E) is 16 but sizeof(F) is 4 ?

Explained above - non virtual methods don't take up memory in the class.

Why siszeof(D) is 8 but sizeof(E) is 16 ?

D only contains the vftable pointer which is apparently 8 bytes on your platform. E also has an int, and the vftable is aligned to 8 bytes. So it's something like:

class E

4 bytes for int |  4 padding bytes  |  8 bytes for vftable pointer  | 
| x | x | x | x |    |    |    |    | v | v | v | v | v | v | v | v |
Claudelle answered 24/2, 2012 at 23:4 Comment(5)
sizeof(uint8_t) == 1 (there's no other possibility), sizeof(char[100]) == 100, etc.Marcellusmarcelo
Padding should probably be mentioned too.Miran
@R.MartinhoFernandes what's sizeof char[53]?Claudelle
@Luchian that wouldn't compile because it needs parentheses, but sizeof(char[53]) is guaranteed to be 53.Marcellusmarcelo
In C++ standards, sizeof(char[100]) is most likely guaranteed 100 (Can someone give me a conformation?), in C it is defined as "AT LEAST 100", where all modern platforms return 100 (Windows, Linux, etcExhort
V
4

Why siszeof(A) is 1 and sizeof(C) is 1 too ?

The function in C is not virtual, so the class doesn't need a vtable pointer, so it needs no more storage than A. Neither A nor C need any storage at all, but because language requires that different instances of the same class have different pointers, they can't have a size of zero - so the compiler makes them as small as it can, i.e. 1 byte.

Why siszeof(H) is 16 but sizeof(G) is 4 ?

G has no virtual functions, so all it needs to store is the int, which on your compiler and architecture is 4 bytes.

H has virtual functions, so the class needs to contain an int and a vtable pointer. All widely used compilers store the vtable pointer at the start of the class, so the layout is {vptr, int}, which is 8+4=12 bytes if you're on a 64 bit host.

However, the compiler is free to pad this out to 16 bytes so that if multiple instances of H are allocated in an array then all of them will be word-aligned. This is important because there are significant performance implications for accessing a pointer (i.e. the vtable pointer here) if it is not word-aligned.

Why siszeof(E) is 16 but sizeof(F) is 4 ?

E has virtual functions, so needs a vtable ptr, so its layout is just like H's. F has no virtual functions, it only has an int, so its layout is just like G's. so the answer's the same as for G and H.

The ordering of the members/functions just doesn't matter here because there's only one member variable and the vtable ptr always goes first if there is one.

Why siszeof(D) is 8 but sizeof(E) is 16 ?

D has no member variables, but it has a virtual function, so it needs a vtable pointer. The vtable pointer is the only thing it needs, so its size is sizeof(void*), which is 8 bytes. E needs the same as D, plus 4 bytes for an integer, and the compiler rounds it up to 16 bytes for alignment.

Valenciavalenciennes answered 24/2, 2012 at 23:16 Comment(0)
T
1
  • sizeof(A)==1

It is so because of C++ standard which prohibits classes/structs of size 0. That's why an empty struct/class have size 1. I find it pretty annoying, but they had some reasoning for that.

  • sizeof(B)==4

That's the size of int, plain and simple :)

  • sizeof(C)==1

That's the size of an empty struct (see A). Nonvirtual functions do not contribute to the object size at all. There is nothing you need to store in an object to be able to call its nonvirtual member function.

  • sizeof(D)==8

I am assuming that you are building a 64-bit application. Any class having at least 1 virtual function has a pointer to a virtual method table. This allows you to call a correct virtual function even if an object pointer was casted to some parent class. Often the pointer is referred to as a vtable. More reading at wiki: http://en.wikipedia.org/wiki/Virtual_method_table

I think the size 8 is coming from that 64-bit pointer.

  • sizeof(E)==16

To store a pointer and an int you technically need 12 bytes. However, a pointer must be aligned to 8 bytes. Now envision yourself creating an array A of objects E. A[0].vtable would have address &A+0, A[0].i would be at &A+8, A[1].vtable would be at &A+12 -- woops, we have a problem, 12 is not divisable by 8. That's why compiler creates a padding. It adds additional useless bytes to make the object align correctly in an array. In this case, the lowest divisable by 8 number is 16. Hence the size.

  • sizeof(F)==4

Same as in case of C - nonvirtual functions do not contribute at all to the size, so your size matches B.

  • sizeof(G)==4 -- same as F

  • sizeof(H)==16

The number of virtual functions does not matter. There is still only one vtable pointer in your object. If you put more virtual functions, the virtual table gets larger, but not the object itself. In many object-oriented programs you often end up with lots of virtual functions. Having pointers stored directly in the object itself would be wasteful.

That's why the size (and the explanation) of H matches the size of E.

Tanked answered 24/2, 2012 at 23:15 Comment(8)
"That's the size of int" - not really. That's the size of int on his platform.Claudelle
Everything is on his platform. Although this is not standard, in most modern compilers int is a 32-bit integer taking 4 bytes. Same goes for empty structs taking 1 byte, etc... I think in the answer to this question it is unnecessary to dwell into platform variety and compiler-implementation specifics.Tanked
On the contrary. For a beginner it's very important to understand what is and isn't platform specific.Claudelle
... but beginner will most likely not work on a system that has non-32-bit integers in any foreseeable future. And when he does, he will be much better educated to know what is and what is not platform specific.Tanked
I don't understand why people would argue that it's okay to say something that is clearly incorrect just because it's very common, or the person asking doesn't need to know the details at this stage, instead of just editing the answer to make it correct.Claudelle
sizeof(D)==8: Caused by compiler specific data structure used to implement virtual functions (potentially a vtable but not necessarily).Aliment
because trying to be perfectly accurate with everything can convey much more information than it is needed and may render the message difficult to understand. Imagine teaching Einstein's theory of relativity without explaining Newton's laws just because the latter is incorrect at relativistic speeds. On the contrary; you usually don't even mention Einstein until very very late.Tanked
@Tanked when I was taught Newtonian physics, the teacher started by saying, I think during every lecture, that it applies to small speeds. This was in 5th grade. I am serious. Romanians... I think any teacher that would try to teach it otherwise is wrong. You don't need to specify relativity, but you should say it's not always true.Claudelle
N
0

why not try printing out the layout? From system V abi

  • dsize(O): the data size of an object, which is the size of O without tail padding.
  • nvsize(O): the non-virtual size of an object, which is the size of O without virtual bases.
  • nvalign(O): the non-virtual alignment of an object, which is the alignment of O without virtual bases.

for example (put your code and remember to apply sizeof to the type you want to check)

struct Base1 {
  virtual int method_base_11() {
    return 11;
  }
  virtual ~Base1() = default;
};

struct Base2 {
  virtual int method_base_21() {
    return 22;
  }
  virtual ~Base2() = default;
};

struct Foo: public Base1, public Base2 {
  int a;
};

int main() {
  Foo foo;
  foo.method_base_21();
  return sizeof(Foo);
}

output,

$ clang -cc1 -std=c++11 -fdump-record-layouts foo.cc

*** Dumping AST Record Layout
         0 | struct Base1
         0 |   (Base1 vtable pointer)
           | [sizeof=8, dsize=8, align=8,
           |  nvsize=8, nvalign=8]

*** Dumping AST Record Layout
         0 | struct Base2
         0 |   (Base2 vtable pointer)
           | [sizeof=8, dsize=8, align=8,
           |  nvsize=8, nvalign=8]

*** Dumping AST Record Layout
         0 | struct Foo
         0 |   struct Base1 (primary base)
         0 |     (Base1 vtable pointer)
         8 |   struct Base2 (base)
         8 |     (Base2 vtable pointer)
        16 |   int a
           | [sizeof=24, dsize=20, align=8,
           |  nvsize=20, nvalign=8]

Nickey answered 31/5, 2020 at 23:55 Comment(0)
P
-1

Size of int with padding and the virtual function =18 bytes

simple function bytes =1 virtual function =8

And you cant simply add all the bytes there is concept of padding check it out on google.

Declaring in different order change the size of class

Preceptive answered 24/2, 2012 at 23:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.