C++
オブジェクトタイプのレイアウト
サーチ…
備考
積分型のサイズも参照してください。
クラスの種類
"class"とは、 class
またはstruct
キーワードを使用して定義された型を意味します( enum struct
またはenum class
はありません)。
空のクラスでも少なくとも1バイトの記憶領域を占有します。したがって、純粋にパディングから構成されます。これにより、
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; };
サブオブジェクトと呼ばれ、
x
の値を含むS
オブジェクト内にsizeof(int)
バイトの連続したシーケンスがあり、y
の値を含むsizeof(char*)
バイトを持つ別のサブオブジェクトがsizeof(char*)
ます。 2つはインターリーブできません。クラス型に型
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
S。このため、alignof
の小さい方の部材の方が、より大きなalignof
部材が追従すると、直後に配置すれば後者の部材が正しく位置合わせされない可能性がある。この場合、2つの部材の間にパッディング( アライメント部材としても知られる)が配置され、後者の部材が所望の位置合わせを有することができる。逆に、より大きなalignof
のメンバーの後ろに小さいalignof
メンバーが続く場合、通常はパディングは必要ありません。このプロセスは「パッキング」とも呼ばれます。
クラスのメンバーは通常、メンバーのalignof
を最大のalignof
で共有するため、クラスは通常、直接的または間接的に含まれる最大の組み込み型のalignof
に整列されます。// 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))
alignas
使用して厳密な配置を強制すると、パディングが使用され、指定された配置が他の方法よりも小さくなっても強制的にそのタイプが満たされます。例えば、以下の定義では、Chars<5>
は最後に3個(あるいはそれ以上)のパディングバイトを挿入し、合計サイズが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");
- あるクラスの2つの非静的メンバーが同じアクセス指定子を持つ場合、後で宣言順になるものは、オブジェクト表現の後に来ることが保証されます。しかし、2つの非静的メンバーが異なるアクセス指定子を持つ場合、オブジェクト内の相対的な順序は指定されません。
- オブジェクト内で基本クラスのサブオブジェクトがどのような順序で表示されるか、それらが連続して出現するかどうか、およびそれらがメンバーのサブオブジェクトの前後に表示されるかどうかは不明です。
算術型
狭い文字タイプ
unsigned char
型は、すべてのビットを使用して2進数を表します。したがって、たとえば、 unsigned char
が8ビット長の場合、 char
オブジェクトの可能な256のビットパターンは、256個の異なる値{0,1、...、255}を表します。番号42は、ビットパターン00101010
によって表されることが保証されている。
signed char
型にはパディングビットはありません。 つまり、 signed char
が8ビット長の場合は、8ビットの容量を持ちます。
これらの保証は、狭い文字タイプ以外のタイプには適用されないことに注意してください。
整数型
符号なし整数型は、純粋なバイナリシステムを使用しますが、パディングビットを含むことがあります。例えば、 unsigned int
が64ビット長であるが、0〜2 32 - 1の間の整数しか格納することはできない(しかし、そうではないかもしれない)可能性がある。他の32ビットはパディングビットであり、直接書き込むべきではない。
符号付き整数型は、符号ビットと場合によってはパディングビットを持つバイナリシステムを使用します。符号付き整数型と対応する符号なし整数型の共通範囲に属する値は、同じ表現を持ちます。たとえば、 unsigned short
オブジェクトのビット・パターン0001010010101011
が値5291
表す場合、 short
オブジェクトとして解釈されたときの値5291
も表します。
3つのシステムがすべて前の段落の要件を満たしているので、2の補数、1の補数、または符号の大きさの表現が使用されるかどうかは、実装によって定義されます。
浮動小数点型
浮動小数点型の値表現は、実装定義です。最も一般的には、 float
型とdouble
型はIEEE 754に準拠し、32ビットと64ビットの長さです( float
は23ビットの精度を持ち、8の指数ビットと1符号ビットに従います)。ただし、この規格では何も保証されていません。浮動小数点型は、しばしば「トラップ表現」を持ち、計算に使用するとエラーを引き起こします。
配列
配列型には要素間にパディングがありません。したがって、要素型T
の配列は、メモリ内にレイアウトされたT
オブジェクトのシーケンスにすぎません。
多次元配列は配列の配列であり、上記は再帰的に適用されます。たとえば、宣言がある場合
int a[5][3];
a
は3 int
の5つの配列の配列です。したがって、 a[0]
、3つの要素から構成されているa[0][0]
a[0][1]
a[0][2]
前に、メモリにレイアウトされているa[1]
から構成されていますa[1][0]
、 a[1][1]
、 a[1][2]
これは、 行の主要な順序と呼ばれます。