Search code examples
c++paddingplacement-new

Is padding important when calling to placement new?


I want to construct B at the place for A.

struct A {
  size_t x;  // 8 bytes
  int i;     // 4 bytes
};           // padding 4 bytes

struct B {
  size_t x;  // 8 bytes
  bool b;    // 1 byte
};           // padding 7 bytes

int main() {
  A a;
  auto p = new(&a) B;
  // auto p = new(std::launder(&a)) B;  // is a bit better
}

Is this code well-defined? Will placement new touch padding bytes (e.g. set all to zeros) or it will work directly with the b bytes?

For example, two A structures are stored contiguously (right after first A::i goes second A::x). If placement new touches padding, second A's data will be corrupted.


Solution

  • There are several things to discuss here.

    • First off, padding is in general unspecified, so you should not assume that you know what and where the padding is. The main constraints are that

      • each scalar subobject has a size and alignment, which must be honoured, and
      • an array of type T[N] has size N * sizeof(T), i.e. there is no "extra array padding". This gives you some minimum padding consequences for T.
    • This means that your "right after first A::i goes second A::st" can't be done; this is not something you get to decide.

    • The placement-new can reuse existing storage, and the main requirement is that the storage is both large enough and suitably aligned for the destination type. You can statically assert these things with sizeof and alignof. The result of the placement-new expression is that the target object (of type B in your example) is initialized (as requested by the chosen initialization syntax), which will potentially write to any and all of the storage occupied by the B object. As per the above requirements, those will be wholly contained within the provided storage, or you already have UB.

    • If you want a whole array A[N] to provide storage for some sequence of objects, then of course it's possible in principle to overwrite the storage of multiple adjacent A objects, but as long as each B object is placement-new-constructed into one specific A object and that one provides sufficient storage (as described above), then no one B object will invalidate any unrelated underlying A objects.