Here is a piece of code which I cannot quite understand:
#include <iostream>
struct Ptr {
void* ptr
#ifdef WAT
= 0
#endif
;
};
struct A {
Ptr ptr;
int d;
};
struct B : public A { int e; };
static_assert(sizeof(A) == 16, "ok");
static_assert(sizeof(B) == 24, "wat");
int main() {
// This code is just to show that the classes are actually used
// by the program
B b;
b.ptr.ptr = new int{};
b.d = b.e = 42;
std::cout << b.ptr.ptr << " " << b.d << " " << b.e << std::endl;
}
I would expect the object sizes to be independent of the initializer for the void* ptr
field. However, there is a difference whether this code is compiled with -DWAT
or not, at least in clang: With -DWAT
, sizeof(B)
is actually 16, which is counter-intuitive to me: https://godbolt.org/z/LFuese
Is there a reasonable intuition for this behaviour? I understand that there are not many guarantees on object layouts, but is there a way to force the "default" behaviour, in the presence of the initializer?
UPDATE: It appears that the layout algorithm differs between objects that have an explicit default constructor / field initializers and such that do not (POD, plain old data type). I still don't understand the logic fully however.