类类型

class 是指使用 classstruct 关键字定义的类型(但不是 enum structenum class)。

  • 即使是空类仍然占用至少一个字节的存储空间; 因此它将纯粹由填充物组成。这确保了如果 p 指向空类的对象,则 p + 1 是一个不同的地址并指向一个不同的对象。但是,当用作基类时,空类的大小可能为 0。查看空基优化

    class Empty_1 {};                               // sizeof(Empty_1)       == 1
    class Empty_2 {};                               // sizeof(Empty_2)       == 1
    class Derived : Empty_1 {};                     // sizeof(Derived)       == 1
    class DoubleDerived : Empty_1, Empty_2 {};      // sizeof(DoubleDerived) == 1
    class Holder { Empty_1 e; };                    // sizeof(Holder)        == 1
    class DoubleHolder { Empty_1 e1; Empty_2 e2; }; // sizeof(DoubleHolder)  == 2
    class DerivedHolder : Empty_1 { Empty_1 e; };   // sizeof(DerivedHolder) == 2
    
  • 类类型的对象表示包含基类的对象表示和非静态成员类型。因此,例如,在以下类中:

    struct S {
        int x;
        char* y;
    };
    

    S 对象中有一个连续的 sizeof(int) 字节序列,称为*子对象,*包含 x 的值,另一个子对象的 sizeof(char*) 字节包含 y 的值。两者不能交错。

  • 如果类类型具有类型为 t1, t2,...tN 的成员和/或基类,则在给定前面的点的情况下,大小必须至少为 sizeof(t1) + sizeof(t2) + ... + sizeof(tN)。但是,根据成员和基类的对齐要求,可能会强制编译器在子对象之间或整个对象的开头或结尾插入填充。

    struct AnInt      { int i; };
      // sizeof(AnInt)        == sizeof(int)
      // Assuming a typical 32- or 64-bit system, sizeof(AnInt)        == 4 (4).
    struct TwoInts    { int i, j; };
      // sizeof(TwoInts)      >= 2 * sizeof(int)
      // Assuming a typical 32- or 64-bit system, sizeof(TwoInts)      == 8 (4 + 4).
    struct IntAndChar { int i; char c; };
      // sizeof(IntAndChar)   >= sizeof(int) + sizeof(char)
      // Assuming a typical 32- or 64-bit system, sizeof(IntAndChar)   == 8 (4 + 1 + padding).
    struct AnIntDerived : AnInt { long long l; };
      // sizeof(AnIntDerived) >= sizeof(AnInt) + sizeof(long long)
      // Assuming a typical 32- or 64-bit system, sizeof(AnIntDerived) == 16 (4 + padding + 8).
    
  • 如果由于对齐要求而在对象中插入填充,则大小将大于成员和基类的大小之和。对于 n 字节对齐,大小通常是 n 的最小倍数,它大于所有成员和基类的大小。每个成员 memN 通常会被放置在一个地址上,该地址是 alignof(memN) 的倍数,而 n 通常是所有成员的 alignof 中最大的 alignof。因此,如果具有较小 alignof 的构件后面跟着具有较大 alignof 的构件,则如果紧接在前者之后放置后者,则后者可能不会正确对齐。在这种情况下,填充(也称为对齐构件 )将被放置在两个构件之间,使得后者可以具有其期望的对准。相反,如果具有较大 alignof 的成员后跟一个具有较小 alignof 的成员,则通常不需要填充。这个过程也称为包装
    由于类通常与最大的会员共享其会员的节目,因此类通常与他们直接或间接包含的最大内置类型的节目 27 对齐。

    // Assume sizeof(short) == 2, sizeof(int) == 4, and sizeof(long long) == 8.
    // Assume 4-byte alignment is specified to the compiler.
    struct Char { char c; };
      // sizeof(Char)                == 1 (sizeof(char))
    struct Int  { int i; };
      // sizeof(Int)                 == 4 (sizeof(int))
    struct CharInt { char c; int i; };
      // sizeof(CharInt)             == 8 (1 (char) + 3 (padding) + 4 (int))
    struct ShortIntCharInt { short s; int i; char c; int j; };
      // sizeof(ShortIntCharInt)     == 16 (2 (short) + 2 (padding) + 4 (int) + 1 (char) +
      //                                    3 (padding) + 4 (int))
    struct ShortIntCharCharInt { short s; int i; char c; char d; int j; };
      // sizeof(ShortIntCharCharInt) == 16 (2 (short) + 2 (padding) + 4 (int) + 1 (char) +
      //                                    1 (char) + 2 (padding) + 4 (int))
    struct ShortCharShortInt { short s; char c; short t; int i; };
      // sizeof(ShortCharShortInt)   == 12 (2 (short) + 1 (char) + 1 (padding) + 2 (short) +
      //                                    2 (padding) + 4 (int))
    struct IntLLInt { int i; long long l; int j; };
      // sizeof(IntLLInt)            == 16 (4 (int) + 8 (long long) + 4 (int))
      // If packing isn't explicitly specified, most compilers will pack this as
      //   8-byte alignment, such that:
      // sizeof(IntLLInt)            == 24 (4 (int) + 4 (padding) + 8 (long long) +
      //                                    4 (int) + 4 (padding))
    
    // Assume sizeof(bool) == 1, sizeof(ShortIntCharInt) == 16, and sizeof(IntLLInt) == 24.
    // Assume default alignment: alignof(ShortIntCharInt) == 4, alignof(IntLLInt) == 8.
    struct ShortChar3ArrShortInt {
        short s;
        char c3[3];
        short t;
        int i;
    };
      // ShortChar3ArrShortInt has 4-byte alignment: alignof(int) >= alignof(char) &&
      //                                             alignof(int) >= alignof(short)
      // sizeof(ShortChar3ArrShortInt) == 12 (2 (short) + 3 (char[3]) + 1 (padding) +
      //                                      2 (short) + 4 (int))
      // Note that t is placed at alignment of 2, not 4.  alignof(short) == 2.
    
    struct Large_1 {
        ShortIntCharInt sici;
        bool b;
        ShortIntCharInt tjdj;
    };
      // Large_1 has 4-byte alignment.
        // alignof(ShortIntCharInt) == alignof(int) == 4
        // alignof(b) == 1
        // Therefore, alignof(Large_1) == 4.
      // sizeof(Large_1) == 36 (16 (ShortIntCharInt) + 1 (bool) + 3 (padding) +
      //                        16 (ShortIntCharInt))
    struct Large_2 {
        IntLLInt illi;
        float f;
        IntLLInt jmmj;
    };
      // Large_2 has 8-byte alignment.
        // alignof(IntLLInt) == alignof(long long) == 8
        // alignof(float) == 4
        // Therefore, alignof(Large_2) == 8.
      // sizeof(Large_2) == 56 (24 (IntLLInt) + 4 (float) + 4 (padding) + 24 (IntLLInt))
    

Version >= C++ 11

  • 如果使用 alignas 强制进行严格对齐,则将使用填充来强制类型满足指定的对齐,即使它会更小。例如,使用下面的定义,Chars<5> 将在末尾插入三个(或可能更多)填充字节,以使其总大小为 8.对于 4 的对齐的类不可能具有 5 的大小,因为制作该类的数组是不可能的,因此必须通过插入填充字节将大小四舍五入到 4 的倍数。

    // This type shall always be aligned to a multiple of 4.  Padding shall be inserted as
    // needed.
    // Chars<1>..Chars<4> are 4 bytes, Chars<5>..Chars<8> are 8 bytes, etc.
    template<size_t SZ>
    struct alignas(4) Chars { char arr[SZ]; };
    
    static_assert(sizeof(Chars<1>) == sizeof(Chars<4>), "Alignment is strict.\n");
    
  • 如果一个类的两个非静态成员具有相同的访问说明符 ,那么稍后在声明顺序中出现的那个成员将保证稍后在对象表示中出现。但是,如果两个非静态成员具有不同的访问说明符,则它们在对象中的相对顺序是未指定的。

  • 未指定基类子对象在对象中出现的顺序,是否它们是连续出现的,以及它们是出现在成员子对象之前,之后还是之间。