空の基底クラス最適化
空の基底サブオブジェクトのサイズをゼロにすることを許可します。
目次 |
[編集] 説明
任意のオブジェクトまたはメンバーサブオブジェクトのサイズは、その型が空のクラス型(つまり、非静的データメンバーを持たないクラスまたは構造体)であっても、少なくとも1である必要があります。([[no_unique_address]]を使用する場合を除く、下記参照)(C++20以降)これは、同じ型の異なるオブジェクトのアドレスが常に異なることを保証できるようにするためです。
しかし、基底クラスサブオブジェクトはそれほど制約を受けず、オブジェクトのレイアウトから完全に最適化して除外することができます。
struct Base {}; // empty class struct Derived1 : Base { int i; }; int main() { // the size of any object of empty class type is at least 1 static_assert(sizeof(Base) >= 1); // empty base optimization applies static_assert(sizeof(Derived1) == sizeof(int)); }
空の基底クラスの1つが、最初の非静的データメンバーの型であるか、その型の基底である場合、空の基底クラス最適化は禁止されます。これは、同じ型の2つの基底サブオブジェクトは、最も派生した型のオブジェクト表現内で異なるアドレスを持つ必要があるためです。
このような状況の典型的な例は、std::reverse_iterator(空の基底std::iteratorから派生)の素朴な実装で、その最初の非静的データメンバーとして基盤となるイテレータ(これもstd::iteratorから派生)を保持する場合です。
struct Base {}; // empty class struct Derived1 : Base { int i; }; struct Derived2 : Base { Base c; // Base, occupies 1 byte, followed by padding for i int i; }; struct Derived3 : Base { Derived1 c; // derived from Base, occupies sizeof(int) bytes int i; }; int main() { // empty base optimization does not apply, // base occupies 1 byte, Base member occupies 1 byte // followed by 2 bytes of padding to satisfy int alignment requirements static_assert(sizeof(Derived2) == 2*sizeof(int)); // empty base optimization does not apply, // base takes up at least 1 byte plus the padding // to satisfy alignment requirement of the first member (whose // alignment is the same as int) static_assert(sizeof(Derived3) == 3*sizeof(int)); }
多重継承が発生する場合、特定の最適化はコンパイラに依存します。
- MSVCでは、ヌル基底クラス最適化は最後のヌル基底クラスにのみ適用され、残りのヌル基底クラスにはヌル基底最適化は適用されず、1バイトが割り当てられます。
- GCCでは、空の基底クラスがいくつ存在しても、空の基底クラスはスペースを割り当てることなく空の基底クラス最適化を適用し、空の基底クラスのアドレスは派生クラスオブジェクトの最初のアドレスと同じになります。
|
空の基底クラス最適化は、StandardLayoutTypesに対して必須です。これは、 |
(C++11以降) |
|
空のメンバーサブオブジェクトは、 このコードを実行 struct Empty {}; // empty class struct X { int i; [[no_unique_address]] Empty e; }; int main() { // the size of any object of empty class type is at least 1 static_assert(sizeof(Empty) >= 1); // empty member optimized out: static_assert(sizeof(X) == sizeof(int)); } |
(C++20以降) |
[編集] 備考
空の基底クラス最適化は、アロケータ対応の標準ライブラリクラス(std::vector、std::function、std::shared_ptrなど)で一般的に使用され、アロケータがステートレスである場合、アロケータメンバーのために追加のストレージを占有することを避けます。これは、必要なデータメンバーの1つ(例:vectorのbegin、end、またはcapacityポインタ)を、アロケータとともにboost::compressed_pairに相当するものに格納することで実現されます。
[編集] 参照
- C++23標準 (ISO/IEC 14882:2024)
- 7.6.10 等価演算子 [expr.eq]
- 7.6.2.5 Sizeof [expr.sizeof]
- 11 クラス [class]
- 11.4 クラスメンバー [class.mem]
- C++20 standard (ISO/IEC 14882:2020)
- 7.6.10 等価演算子 [expr.eq]
- 7.6.2.4 Sizeof [expr.sizeof]
- 11 クラス [class]
- 11.4 クラスメンバー [class.mem]
- C++17 standard (ISO/IEC 14882:2017)
- 8.10 等価演算子 [expr.eq]
- 8.3.3 Sizeof [expr.sizeof]
- 12 クラス [class]
- 12.2 クラスメンバー [class.mem]
- C++14 standard (ISO/IEC 14882:2014)
- 5.10 等価演算子 [expr.eq]
- 5.3.3 Sizeof [expr.sizeof]
- 9 クラス [class]
- 9.2 クラスメンバー [class.mem]
- C++11 standard (ISO/IEC 14882:2011)
- 5.10 等価演算子 [expr.eq] (p: 2)
- 5.3.3 Sizeof [expr.sizeof] (p: 2)
- 9 クラス [class] (p: 4,7)
- 9.2 クラスメンバー [class.mem] (p: 20)
- C++98 標準 (ISO/IEC 14882:1998)
- 5.10 等価演算子 [expr.eq] (p: 2)
- 5.3.3 Sizeof [expr.sizeof] (p: 2)
- 9 クラス [class] (p: 3)
[編集] 外部リンク
| More C++ Idioms/Empty Base Optimization — Wikibook |