Take the typical demonstration of how pointer values can change through casting:
struct B1 { int x; };
struct B2 { int y; };
struct D : B1, B2 { };
int main() {
D d;
cout << (B1*)&d << " " << (B2*)&d << " " << &d;
}
// Typical output:
// 0xbf814ab4 0xbf814ab8 0xbf814ab4
I got to thinking; that offset probably does not exist when B1 has no members, so I checked and it’s true (at least in this case; not sure how standards-guaranteed this behaviour is):
struct B1 { };
struct B2 { };
struct D : B1, B2 { };
int main() {
D d;
cout << (B1*)&d << " " << (B2*)&d << " " << &d;
}
// Typical output:
// 0xbf6ad95b 0xbf6ad95b 0xbf6ad95b
But then, sizeof(T) cannot be 0, so sizeof(B1) is still 1.
It strikes me that this “discrepancy” may potentially cause serious error-prone code where a programmer assumes that (char*)(B2*)&d - (char*)(B1*)&d == (ptrdiff_t)sizeof(B1).
Is my analysis accurate?
The
B1andB2objects are subobjects ofd. Thesizeofoperator gives information about the size of a complete object, not a subobject.The Standard allows but does not require a base class subobject to occupy no memory. So on another compliant implementation, you could find in your second example that the subobjects have different addresses after all.
And the only "safe" uses of pointer arithmetic are:
yof complete objectxis between&xinclusive and&x+1exclusive.Subtracting two
void*pointers is ill-formed. You probably meant toreinterpret_cast<char*>or something. (Another sign that the code is very risky.)