Consider this example:
#include <iostream>
int main()
{
struct A {};
struct B : A {};
struct C : A, B {};
std::cout << sizeof(A) << '\n'; // 1
std::cout << sizeof(B) << '\n'; // 1
std::cout << sizeof(C) << '\n'; // 2, because of a duplicate base
struct E : A {virtual ~E() {}};
struct F : A, B {virtual ~F() {}};
std::cout << sizeof(E) << '\n'; // 8, the base overlaps the vtable pointer
std::cout << sizeof(F) << '\n'; // 16, but why?
}
(run on godbolt)
Here you can see that for struct E
the empty base class (which is 1 byte large) uses the same storage as the vtable pointer, as expected.
But for struct F
, which has a duplicate empty base, this doesn't happen. What causes this?
I get the same result on GCC, Clang, and MSVC. The results above are for x64, so sizeof(void *) == 8
.
Interestingly, for struct G : A, B {void *ptr;};
GCC and Clang do perform EBO (the size is 8), but MSVC doesn't (the size is 16).
Because the compiler adds one byte padding after struct A
F {vptr(8) + 0 members from A + 1 padding (because A is empty)+0 from b} = 9 then the compiler add 7 bytes padding to align storage of the struct;
E {vptr(8) + 0 members for A} = 8 No padding required
from Microsoft
Every data object has an alignment-requirement. For structures, the requirement is the largest of its members. Every object is allocated an offset so that offset % alignment-requirement == 0
https://docs.microsoft.com/en-us/cpp/c-language/storage-and-alignment-of-structures?view=vs-2019
EDIT:
here is my demo:
int main()
{
C c;
A* a = &c;
B* b = &c;
std::cout << sizeof(A) << " " << a << '\n';
std::cout << sizeof(B) << " " << b << '\n';
std::cout << sizeof(C) << " " << &c << '\n';
E e;
a = &e;
std::cout << sizeof(E) <<" " << &e << " " << a << '\n';
F f;
a = &f;
b = &f;
std::cout << sizeof(F) << " " << &f << " " << a << " " << b << '\n';
}
output:
1 0000007A45B7FBB4
1 0000007A45B7FBB5
1 0000007A45B7FBB4
8 0000007A45B7FC18 0000007A45B7FC20
16 0000007A45B7FC38 0000007A45B7FC40 0000007A45B7FC41
as you can see a & b never overlaps with each other and with vptr on multiple inheritance each has its own pointer value
note compiled by VC2019 x64 build
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With