Most C++ programmers know about the empty base class optimazation as a technique/idiom. What happens with empty child classes? For example
c
The standard does not contain an "empty base class" case per se. Rather, it says (cf. 1.8):
[A] most derived object shall have a non-zero size and shall occupy one or more bytes of storage. Base class subobjects may have zero size.
And:
Unless an object is [...] a base class subobject of zero size, the address of that object is the address of the first byte it occupies. Two objects [...] may have the same address if one is a subobject of the other, or if at least one is a base class subobject of zero size and they are of different types; otherwise, they shall have distinct addresses.
And (Clause 9):
Complete objects and member subobjects of class type shall have nonzero size. Footnote: Base class subobjects are not so constrained.
This never says that only empty bases are amenable to any kind of layout change and leaves ample room for "squeezing" the layout: for example:
struct A {}; struct B : A { int x; }; // "equivalent" to { int }
struct X { int a; }; struct Y : X {}; // "equivalent" to { int }
Consider B b;
and Y y;
. it is possible that the address of b
, that of the A
-subobject of b
(i.e. &static_cast<A&>(b)
) and that of b.x
are the same, and similarly that the address of y
, the X
-suboject of y
, and the address of y.a
are the same.
The only thing that does not work is this:
struct S {}; struct T { S s; }; // "equivalent" to { char }
By "equivalent"
I mean the most sensible, space-saving implementation.
A more interesting case is the following:
struct Foo { int x; char a; }; // { int, char, char[3] }
struct Bar : Foo { short q; }; // { int, char, char, short }
This example assumes sizeof(int) == 4
and sizeof(short) == 2
. We have sizeof(Foo) == 8
for alignment reasons, but sizeof(Bar)
is also 8
despite having more data members.
Another relevant part of the standard is 9.2/13:
Nonstatic data members of a (non-union) class with the same access control (Clause 11) are allocated so that later members have higher addresses within a class object. The order of allocation of non-static data members with different access control is unspecified (11). Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other; so might requirements for space for managing virtual functions (10.3) and virtual base classes (10.1).
Finally, 9.2/10 says that standard-layout classes have no padding at the beginning, so that their address equals the address of their "initial member". Since standard-layout requires that all bases either be empty, or that the most-derived class itself have no data members, this means that standard-layout classes must employ a kind of "empty base" optimization, and the initial part of the layout of my B
and Y
above is actually mandatory.