Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Optimizing class layout by minimizing padding safely

I have the following type and my goal is to optimize the size of Storage:


struct Inlined   { int  data[9];              };            // sizeof => 36
struct Allocated { int* data; size_t capacity };            // sizeof => 16
union  Data      { Inlined inlined; Allocated allocated; }; // sizeof => 40

struct Storage {                                            // sizeof => 56
  size_t size;
  bool is_allocated;
  Data data;
};

I understand that sizes and layout may vary between compilers and platforms. My goal is to get more compact layout on at least some compilers/platforms.

As you can see in my example, Data has 4 bytes of padding because Inlined and Allocated have different alignments and Data is 8-byte aligned. I am trying to find a way to squeeze boolean is_allocated into this padding.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

So far, I came up with the following structure and I would really appreciate if someone can confirm or deny "safety" / "legalness" of such type:

struct CompactStorage {                                      // sizeof => 48
  size_t size;
  union {
    struct {
      bool is_allocated;
      Inlined inlined;
    };
    struct {
      bool copy_of_is_allocated;
      Allocated allocated;
    };
  };
};

To clarify, by safety I mean that I expect CompactStorage::is_allocated and CompactStorage::copy_of_is_allocated to be aliasing the same memory. And I expect that if I write to CompactStorage::is_allocated then it does not overwrite bytes aliased by CompactStorage::allocated (and vice versa). If that does not hold, then I consider CompactStorage unsafe as it cannot be used as a replacement for Storage.

P.S. I know about bitfields and deliberately do not use them due to (proven) performance implications.

>Solution :

This is very much well-defined. From [class.mem]

In a standard-layout union with an active member of struct type T1, it is permitted to read a non-static data member m of another union member of struct type T2 provided m is part of the common initial sequence of T1 and T2; the behavior is as if the corresponding member of T1 were nominated.

Where common initial sequence is

The common initial sequence of two standard-layout struct types is the longest sequence of non-static data members and bit-fields in declaration order, starting with the first such entity in each of the structs, such that corresponding entities have layout-compatible types […]

Which means you may use is_allocated and copy_of_is_allocated interchangeably, given that the structs are standard-layout types.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading