2

I am learning about memory alignment. I think I understand the concept and I just want to make sure if I understand the practice correctly with an example.

I have 2 classes like below

class Base {
   int64_t a;
   int64_t b;
   int64_t c;
   int64_t d;

   virtual void method();
}

class A: public Base {
    // 8 bytes virtual pointer
    // 32 bytes Base object
    // 16 bytes C struct
    C data;

   void method() override;
}

Right now class A sits at 56 bytes. To make A memory aligned when using it in an array, I am thinking it needs 8 more padding bytes because 64 is divisible by 32, which is the largest member of the class. My first question is that Im not sure if I need it, cause in reality Base's member is actually 8 byte aligned. And even if I do need it, should I put the 8 bytes padding before member "data" or after "data". I'm thinking before "data" because C is 16 bytes, and putting it before "data" would mean that "data" starts at byte 48, divisible by 16.

Thanks in advance.

Edit: I forgot to include this, but A actually overrides some virtual methods from Base. That's where the virtual table pointer comes from

Henry Wise
  • 367
  • 1
  • 9
  • 1
    Where is `// 8 bytes virtual pointer` coming from? – NathanOliver Aug 12 '19 at 18:19
  • First, it doesn't look like `A` is polymorphic, so it doesn't need a virtual pointer. Second, if an object is polymorphic, it's not specified how much that increases the size of your type by. – François Andrieux Aug 12 '19 at 18:19
  • 1
    how do you get 32 bytes for `Base` ? also there is nothing virtual in your example – 463035818_is_not_an_ai Aug 12 '19 at 18:20
  • 1
    See https://en.cppreference.com/w/cpp/language/alignas and https://en.cppreference.com/w/cpp/language/alignof – Jesper Juhl Aug 12 '19 at 18:26
  • @formerlyknownas_463035818 deleted the calculations and comment. Anyway, indeed nothing forbids unless `__attribute__((__packed__))` is used to tell the compiler not to add padding – Tony Tannous Aug 12 '19 at 18:26
  • somewhat related: https://stackoverflow.com/questions/5709892/do-all-classes-have-a-vtable-created-for-them-by-the-compiler – 463035818_is_not_an_ai Aug 12 '19 at 18:27
  • Don't forget that you can often reduce the amount of padding needed by your class, between members (reducing its overall size), by reordering/sorting its member variables (from largest alignment requirement to smallest). – Jesper Juhl Aug 12 '19 at 18:31
  • @formerlyknownas_463035818: `class Base` meets the requirement for standard-layout (not virtual, all subobjects are standard-layout, only one type of subobject -- no mixing of bases and members, and all members appear within one access block). So the compiler has to use standard layout and cannot insert any padding not absolutely needed for alignment. – Ben Voigt Aug 12 '19 at 18:34
  • @BenVoigt thanks for correcting. deleted misleading comment – 463035818_is_not_an_ai Aug 12 '19 at 18:36
  • Henry, you don't need any padding here. `class Base` may have size 32 but it only needs 8 byte alignment, which when class A is 56 bytes already meets. – Ben Voigt Aug 12 '19 at 18:36
  • @BenVoigt I have updated the question because I forgot about the virtual methods. Thank you for your answer to my first question. What do you think about my 2nd question? Cause I will still need 8 byte before "data" member so that "data" starts at 48th byte, right? – Henry Wise Aug 12 '19 at 19:19
  • Now `class Base` definitely doesn't have size 32, and no longer is standard layout. But the compiler is still smart enough to make the sizes of both classes be a multiple of the alignment requirement; you don't have to do anything special in order to use it in an array (although beware that arrays and virtual member functions do not play nicely together) – Ben Voigt Aug 12 '19 at 21:27

1 Answers1

1

We can align a class very simply:

// This class is aligned to the same alignment as int
class UnalignedClass {
    int x, y, z;
};

// This class is now aligned to 16 byte boundaries
class alignas(16) AlignedClass {
    int x, y, z;
};

In the same way, if you want to align a derived class, you can just do:

class Base {
   int64_t a;
   int64_t b;
   int64_t c;
   int64_t d;
};
class C {
    char data[16];
};

class alignas(64) A: public Base {
    // No virtual pointer, since Base contains no virtual methods
    // 32 bytes Base object
    // 16 bytes C struct
    C data;
};

If we print out the size and alignment, we can see that A has a size and alignment of 64, and the compiler adds the extra padding automatically.

#include <iostream>
int main() {
    std::cout << sizeof(A) << '\n'; 
    std::cout << alignof(A) << '\n'; // Prints 64
}

That being said, you probably don't need to manually align your classes. If left unspecified, the alignment of the class will be the alignment of the member with the biggest alignment. For example:

class alignas(64) Foo {}; // Foo aligned to 64 bytes

class Bar {   // Bar is ALSO aligned to 64 bytes, since it contains a Foo
    int x;
    int y;
    Foo f; 
};
Alecto Irene Perez
  • 10,321
  • 23
  • 46