Is tail padding of a base class guaranteed not to be reused by a derived class if the base class is an aggregate?

Viewed 94

There are many many questions from surprised C++ programmers who notice that tail padding is reused only when the base class is not a POD type.

For example, the following code works on x86-64 gcc (godbolt link):

struct A {
    int a;
    bool aa;
};
struct B : A {
    bool b;
};
struct C : B {
    bool c;
};
static_assert(sizeof(A) == 8);
static_assert(sizeof(B) == 12);
static_assert(sizeof(C) == 12);

This means that the field c is placed into the padding of B, but the field b is not placed into the padding of A.

The linked questions only explain that a particular ABI specifies this layout, and one answer goes as far as to say that reusing the tail padding of a POD type "breaks common assumptions a programmer would make", and so "basically any sane compiler won't do tail padding reuse" for such types. However, this explanation is unsatisfactory because it doesn't actually guarantee anything.

Does the standard guarantee that the tail padding of a POD type will not be reused by a derived class?

1 Answers

Being an aggregate matters for exactly one thing: aggregate initialization. It has nothing to do with the layout of the members of a type.

That is governed by the layout rules. A is standard layout, which is a subset of types that have certain layout guarantees. Classes B and C are not standard layout (or POD, or whatever you'd like to call it), so there is much more variance permitted in the layout of those types.

The standard permits any of the implementations specifies by the other answers. They're all equally valid.

It's OK for a type to use the padding in non-empty base classes for its own subobjects. This is in part because doing things like memcpy into base class subobjects (or any other potentially-overlapping subobject) is expressly forbidden:

For any object (other than a potentially-overlapping subobject) of trivially copyable type T ...

Related