Sizeof a class
To follow up on my
previous post, here are some more cool things I learned about sizeof and classes in C++. I've been doing a lot of fun stuff with serializing and de-serializing classes with c-style casts to and from byte pointers, because it works fantastically well and very quickly and lends itself well to storage. Of course there are safer ways to do it, but that's the beauty of the things I'm doing - overhead is cut out whenever possible. So, fun learnings. A small overview first, and the rest after the jump.
Let's use well-recognizable types, defined in
. (See my
previous article about sizes.) Let's assume we're on a 32-bit system and pointers are 32 bits in size.
1234567 | class Foo {
public:
int8_t a_byte;
int16_t a_short;
uint32_t a_uint;
uintptr_t a_ptr;
};
|
What do we get from
? It's fairly simple, by inspection, to count the bytes: 1 + 2 + 4 + 4 (because we assumed 32-bit system, 32-bit pointers) = 11 B. But now let's check out the more interesting cases after the jump.
123456789 | class Foo {
public:
int8_t a_byte;
int16_t a_short;
uint32_t a_uint;
uintptr_t a_ptr;
public:
static ui32_t a_static_uint;
};
|
We've added a static member variable, yet
. Why? Simply put, a static variable in this context doesn't belong to any instance of the class, and
sizeof
measures the size of an instance. The variable is more of a global, stored globally, with class scope. The terminology here may be imprecise (or wrong) but I think the meaning is clear: no instance owns the static member variable, therefore it doesn't count for its size.
How about an empty class?
Looks like zero.
. Hum! Apparently, the minimum size for a class is 1 byte, since we want to make sure that different instances of the class are allocated a non-zero size, so that they are then given different addresses. It's easy to see that if the class had a zero size, it could be given the same address as something else -- if
malloc
(or
new
) allocates linearly, by giving an address to use then moving the pointer to the next available address, a zero-size allocation wouldn't move the pointer. Oops!
How about an inherited class?
12345678 | class Foo {
public:
uint32_t a_uint;
};
class Bar : public Foo {
public:
uint32_t another_uint;
};
|
As you might guess,
.
Adding virtual functions means creating a virtual table pointer, which adds the pointer size.
123456789101112 | class Foo {
public:
uint32_t a_uint;
public:
virtual void do_things();
};
class Bar : public Foo {
public:
uint32_t another_uint;
public:
virtual void do_stuff();
};
|
Now
and
. Note that Bar has inherited the virtual pointer table requirement and the extra virtual function hasn't added anything to its size!
There's more to it, depending on the compiler, and other modes of inheritance, but that's all I care about for now.
Ches Koblents
October 3, 2014