Empty derived optimization

后端 未结 1 1709
迷失自我
迷失自我 2021-01-12 19:50

Most C++ programmers know about the empty base class optimazation as a technique/idiom. What happens with empty child classes? For example

c         


        
相关标签:
1条回答
  • 2021-01-12 20:10

    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.

    0 讨论(0)
提交回复
热议问题