名前空間
変種
操作

空の基底クラス最適化

From cppreference.com
< cpp‎ | language
 
 
C++言語
全般
フロー制御
条件実行文
if
繰り返し文 (ループ)
for
範囲for (C++11)
ジャンプ文
関数
関数宣言
ラムダ式
inline指定子
動的例外仕様 (C++17まで*)
noexcept指定子 (C++11)
例外
名前空間
指定子
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点数
文字 - 文字列 - nullptr (C++11)
ユーザー定義 (C++11)
ユーティリティ
属性 (C++11)
typedef宣言
型エイリアス宣言 (C++11)
キャスト
メモリ確保
クラス
クラス固有の関数プロパティ
explicit (C++11)
static

特殊メンバ関数
テンプレート
その他
 
 

空の基底サブオブジェクトのサイズをゼロにすることを許可します。

目次

[編集] 説明

任意のオブジェクトまたはメンバーサブオブジェクトのサイズは、その型が空のクラス型(つまり、非静的データメンバーを持たないクラスまたは構造体)であっても、少なくとも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に対して必須です。これは、reinterpret_castを使用して変換された標準レイアウトオブジェクトへのポインタがその初期メンバーを指すという要件を維持するためです。このため、標準レイアウト型の要件には、「すべての非静的データメンバーが同じクラスで宣言されている(派生クラスにすべて、または何らかの基底クラスにすべて)」および「最初の非静的データメンバーと同じ型の基底クラスを持たない」が含まれます。

(C++11以降)

空のメンバーサブオブジェクトは、[[no_unique_address]]属性を使用する場合、空の基底クラスと同様に最適化して除外することが許可されます。そのようなメンバーのアドレスを取得すると、同じオブジェクトの他のメンバーのアドレスと等しくなる可能性があります。

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::vectorstd::functionstd::shared_ptrなど)で一般的に使用され、アロケータがステートレスである場合、アロケータメンバーのために追加のストレージを占有することを避けます。これは、必要なデータメンバーの1つ(例:vectorbeginend、または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
English 日本語 中文(简体) 中文(繁體)