I've discovered some inconsistencies between compilers with this program,
struct A {
};
struct B : public A {
float m;
};
struct C : public A {
B b;
float n;
};
struct D : public A {
float n;
B b;
};
static_assert(sizeof(A) == 1, "");
static_assert(sizeof(B) == 4, "");
static_assert(sizeof(C) == 8, ""); // most compilers say this is 12
static_assert(sizeof(D) == 8, "");
Most compilers assert on sizeof(C) == 8 saying that the sizeof(C) is actually 12. The only compiler I've found that doesn't and says it's 8 is Microsoft Visual Studio 2010.
The reason I've been told, by someone smarter then me, is that there are two separate references of A within B that need to retain individual offsets different from one another. First, the A derived from C is at offset 0 and the second A inside member b can not be at the same offset as the first A at 0 so 4 bytes of padding is inserted.
As most compiler's have implemented this behavior I was wondering what case do you need to make sure both A's have different references? Looking for some intuition on why this is the case?
Someone said it may be a condition required by the standard and we were curious on what is the reason for it?
Thank you
The standard definitely mandates that the address of each object of the same type is different. The relevant clause is 5.10 [expr.eq] paragraph 1:
Two pointers of the same type compare equal if and only if they are both null, both point to the same function, or both represent the same address (3.9.2).
This is needed to, well, distinguish the two objects. Objects have both a value and an identity. For a base class subobject it is reasonable to have the same address as the containing class. For a member of a class, you can distinguish the identity of the two objects by their type, i.e., it is OK for them to have the same address. For two object of the same type you'd still need something to distinguish the objects for their identity.