In C ++ 11, the compiler should use empty base class optimization for standard layout types. see stack overflow.
In your specific example, all types are standard layout classes and do not have common base classes or members (see below), so you can rely on this behavior in C ++ 11 (and in practice, I think many compilers have already followed this the rule, of course, is g ++, while others are Itanium C ++ ABI .)
Caution: make sure you do not have base classes of the same type, because they must be at different addresses, for example.
struct I {}; struct J : I {}; struct K : I { }; struct X { int i; }; struct Y : J, K, X { }; #include <iostream> Y y; int main() { std::cout << &y << ' ' << &y.i << ' ' << (X*)&y << ' ' << (I*)(J*)&y << ' ' << (I*)(K*)&y << '\n'; }
prints:
0x600d60 0x600d60 0x600d60 0x600d60 0x600d61
For type Y only one of the bases I can be at zero offset, therefore, if the sub-object X is at zero offset (i.e. offsetof(Y, i) is zero), and one of I based on the same address, but another I base is (at least with g ++ and Clang ++) one byte per object, so if you received I* you could not reinterpret_cast before X* because you don't know which <sub-object I it is indicated I with offset 0 or I with offset 1.
OK, so that the compiler puts the second object I at offset 1 (i.e. inside int ), because I does not have non-static data elements, so you cannot actually dereference or access anything at this address, just get a pointer to the object at this address. If you added non-static data members to I , then Y will no longer be the standard layout and it will not need to use EBO, and offsetof(Y, i) will no longer be zero.
Jonathan wakely
source share