2017-01-16 2 views
9

私はデータなしでクラスがあるとします。サイズ

struct Empty { 
    /*some methods here*/ 
}; 

そして派生クラスの空のクラスの

struct Derived: Empty { 
    int a; 
    int b; 
    char c; 
    .... 
}__attribute__((packed));` 

オブジェクトは、サイズ、派生クラスの= 1.空の部分を持っています通常、サイズは0です。コンパイラが理解するように、ベースのEmptyクラスにはデータがないので、Emptyのサイズを「内部」の場合に最適化することができます。ただし、標準で行う必要はありません。

そこで質問です:

私は何とか派生クラスの空の一部が実際にメモリを占有していないことをコンパイル時に決定することができます。

私はsizeof(Derived) = sizeof(a) + sizeof(b) ...のようなチェックをすることができると私は理解しますが、あまりにも冗長であり、派生のようないくつかのクラスがあります。より洗練されたソリューションはありますか?

+0

なぜ知りたいですか?メンバまたは基底クラスは、派生クラスのフットプリントに追加することなく(パディングに失われたスペースを使用して)メモリを占有することができます。また、構造体の 'sizeof'はメンバーと基底の' sizeof'の合計よりも小さくても大きくてもかまいません。 – skyking

+0

これらのDerivedクラスを使用して、ネットワークデータを表現します。そのようなDerivedクラスはすべて、packed属性を持ちます。また、私はCuriously Recurring Template Patternを実装するためにいくつかのテンプレートクラスを継承するつもりです。したがって、派生クラスには共通の機能がいくつかあります。しかし、私はこの継承がDerivedクラスのレイアウトに影響しないことを望んでいます。 –

答えて

11

あなたが継承しているクラスがゼロサイズであることを確認するstd::is_emptyを使用することができます。

static_assert(std::is_empty<Empty>{}); 

を、それがある場合は、empty base optimizationguaranteed to take place for standard-layout classesです。


は私がsizeof(Derived) = sizeof(a) + sizeof(b) ...のようにチェックしますかすることができますが、それはあまりにも冗長であることを理解しています。より洗練されたソリューションはありますか?

packedのような最終的な属性とアカウントにパディングする必要があるため、これは正しく機能しません。

あなたは( 11 C++前)マクロより "古い" を使用することができ
+0

ありがとうございます。この最適化が保証されているか分かりませんでした。 –

+0

標準ではこの最適化が保証されていません。現実のコンパイラでは実際にはかなり一般的です。 – Peter

+1

@Peter:[* standard-layout *クラスについては保証されています](http://stackoverflow.com/questions/10788823/is-theempte-base-class-optimization-now-a-mandatory-optimization-at -least-for)。私は私の答えを明確にします。 –

3

からoffsetof

static_assert(offsetof(Derived,a) < offsetof(Derived,b),""); 
static_assert(offsetof(Derived,b) < offsetof(Derived,c),""); 
を:あなたはあまりにもあなたのメンバ変数の順序を確認するために、このマクロを使用することができます

struct Empty {}; 
struct NonEmpty { 
    int a; 
}; 
struct Derived1: Empty { 
    int a; 
    int b; 
    char c; 
}; 
struct Derived2: NonEmpty { 
    int a; 
    int b; 
    char c; 
}; 
static_assert(offsetof(Derived1,a) == 0,""); 
static_assert(offsetof(Derived2,a) != 0,""); 

しかし、忘れてはいけない - offsetofは、同じ制限があります。

タイプではない場合標準のレイアウトタイプでは、動作は未定義です。 メンバが静的メンバまたはメンバ関数の場合、動作は未定義です。