27

According to C++11 9.1/7 (draft n3376), a standard-layout class is a class that:

  • has no non-static data members of type non-standard-layout class (or array of such types) or reference,

  • has no virtual functions (10.3) and no virtual base classes (10.1),

  • has the same access control (Clause11) for all non-static data members,

  • has no non-standard-layout base classes,

  • either has no non-static data members in the most derived class and at most one base class with non-static data members, or has no base classes with non-static data members, and

  • has no base classes of the same type as the first non-static data member.

it follows that an empty class is a standard-layout class; and that another class with an empty class as a base is also a standard-layout class provided the first non-static data member of such class is not of the same type as the base.

Furthermore, 9.2/19 states that:

A pointer to a standard-layout struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa. [ Note: There might therefore be unnamed padding within a standard-layout struct object, but not at its beginning, as necessary to achieve appropriate alignment. —end note]

This seems to imply that the Empty Base Class Optimization is now a mandatory optimization, at least for standard-layout classes. My point is that if the empty base optimization isn't mandated, then the layout of a standard-layout class would not be standard but rather depend on whether the implementation implements or not said optimization. Is my reasoning correct, or am I missing something?

Community
  • 1
  • 1
K-ballo
  • 80,396
  • 20
  • 159
  • 169
  • Your title seems misleading -- it's a given that empty bases do not break standard layout, and your question seems to be more about empty base optimization. – ildjarn May 28 '12 at 18:26
  • @ildjarn: My point is that if the empty base optimization isn't mandated, then the layout of a _standard-layout_ class would not be standard but depend on whether the implementation implements or not the optimization. But _9.2/19_ seems to mandate such optimization. If you could suggest a better title, I'd happily change it. – K-ballo May 28 '12 at 18:29
  • 1
    You're reasoning seems correct. Post it as your own answer. ;) – edA-qa mort-ora-y May 28 '12 at 18:31
  • Your last paragraph sums it up nicely I think -- something like "Is the Empty Base Class Optimization now a mandatory optimization, at least for standard-layout classes?" – ildjarn May 28 '12 at 18:32
  • I think you are misinterpreting the text. The first member of a derived class is the base class (empty, or not). – Bo Persson May 28 '12 at 18:35
  • I don't get it. A "standard layout" class will almost certainly differ for reasons such as type sizes and alignment. (What's the size of a standard layout class consisting of a single int member?) It was never guaranteed that "standard layout" classes were bitwise identical across all C++ implementations. –  May 28 '12 at 19:11
  • @hvd: I would expect the layout of a _standard-layout_ class to change based on type sizes and alignment, but I wouldn't expect it to change based on whether a particular optimization was applied or not. – K-ballo May 28 '12 at 19:20
  • @K-ballo Agreed, that optimisation becomes more than merely an optimisation, it becomes part of the ABI. And all compilers that conform to a fixed ABI must either all perform EBO, or must all not perform EBO. However, multiple distinct ABIs can be used on the same platform without any problems. –  May 28 '12 at 19:26
  • @K-ballo FWIW, I'm not at all saying that EBO *isn't* required, merely that I don't follow your reasoning for why it *should* be required. –  May 28 '12 at 19:27
  • @hvd: Assuming _EBO_ is not mandated and an implementation can decide to apply it or not on a case by case basis, whether two _standard-layout_ classes are layout compatible or not would depend on whether the optimization is applied or not. – K-ballo May 28 '12 at 19:35
  • @K-ballo Yes, a compiler must not randomly choose to apply EBO in one compilation and not in the next, just as a compiler must not make sizeof(int) 2 in one compilation and 4 in the next, because changing whether EBO is done changes the ABI. But that works both ways: in order to conform to the ABI of the default compiler for a platform, if that default compiler does not perform EBO, the other compiler mustn't either. (And if C++11 requires EBO, and a compiler doesn't perform EBO, it becomes impossible to create a conforming implementation with the same ABI.) –  May 28 '12 at 19:42
  • @BoPersson "_The first member of a derived class is the base class (empty, or not)._" since when is a base class considered a member? – curiousguy Jul 11 '12 at 01:34

1 Answers1

23

Yes, you're correct, that was pointed out in the "PODs revisited" proposals: http://www.open-std.org/jtc1/sc22/WG21/docs/papers/2007/n2342.htm#ABI

The Embarcadero compiler docs also state it: http://docwiki.embarcadero.com/RADStudio/en/Is_standard_layout

Another key point is [class.mem]/16

Two standard-layout struct (Clause 9) types are layout-compatible if they have the same number of non-static data members and corresponding non-static data members (in declaration order) have layout-compatible types (3.9).

Note that only data members affect layout compatibility, not base classes, so these two standard layout classes are layout-compatible:

struct empty { };
struct stdlayout1 : empty { int i; };

struct stdlayout2 { int j; };
Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • Is "initial sequence" actually defined? Where? What is it? Are base subobjects actually guaranteed to come first, before members? – Kerrek SB Feb 17 '14 at 20:28
  • I.e. if I have `struct A { char x[17]; }; struct B { char x[9]; };`, could it be that `struct Foo : A { int foo; };` and `struct Bar : B { int bar; }` have the same initial sequence, because they both start with `int`? – Kerrek SB Feb 17 '14 at 20:29
  • 3
    Ah, never mind! To be standard layout, you cannot have data members both in a base and in the most-derived class. Problem solved. – Kerrek SB Feb 17 '14 at 20:33