Empty base optimization
空の基底サブオブジェクトのサイズをゼロにできるようにする。
目次 |
説明
任意の
オブジェクト
またはメンバー部分オブジェクトのサイズは、たとえ型が空の
クラス型
(非静的データメンバーを持たないクラスまたは構造体)であっても、少なくとも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 {}; // 空クラス struct Derived1 : Base { int i; }; struct Derived2 : Base { Base c; // Base、1バイトを占有し、その後iのためのパディングが続く int i; }; struct Derived3 : Base { Derived1 c; // Baseから派生、sizeof(int)バイトを占有 int i; }; int main() { // 空基底クラス最適化は適用されない、 // 基底クラスは1バイトを占有、Baseメンバは1バイトを占有 // その後intのアライメント要件を満たすための2バイトのパディングが続く static_assert(sizeof(Derived2) == 2*sizeof(int)); // 空基底クラス最適化は適用されない、 // 基底クラスは少なくとも1バイトと、最初のメンバの // アライメント要件を満たすためのパディングを占有 // (そのアライメントはintと同じ) static_assert(sizeof(Derived3) == 3*sizeof(int)); }
|
空基底クラス最適化は、
StandardLayoutType
s
において、
|
(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つ(例:
begin
、
end
または
capacity
ポインタ for
vector
)をアロケータとの
boost::compressed_pair
相当の構造に格納することで実現されます。
MSVCでは、空の基底クラス最適化は標準要件に完全に準拠していません( Why is the empty base class optimization (EBO) is not working in MSVC? )。
参考文献
- 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標準 (ISO/IEC 14882:2020):
-
- 7.6.10 等価演算子 [expr.eq]
-
- 7.6.2.4 Sizeof演算子 [expr.sizeof]
-
- 11 クラス [class]
-
- 11.4 クラスメンバ [class.mem]
- C++17標準 (ISO/IEC 14882:2017):
-
- 8.10 等価演算子 [expr.eq]
-
- 8.3.3 Sizeof演算子 [expr.sizeof]
-
- 12 クラス [class]
-
- 12.2 クラスメンバ [class.mem]
- C++14 標準 (ISO/IEC 14882:2014):
-
- 5.10 等価演算子 [expr.eq]
-
- 5.3.3 Sizeof 演算子 [expr.sizeof]
-
- 9 クラス [class]
-
- 9.2 クラスメンバ [class.mem]
- C++11標準 (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 — ウィキブック |