Empty class and optimization


What is empty class and why worth optimization
Empty classはその名の通り空のクラスです.例えば
class empty {};

ここでemptyは らかに のクラスで、 のメンバーもいません.ただし、 クラスはこの に されず、メンバー のみでnon-static data memberがないクラスについては、 クラスであってもよい.
class empty
{
public:
    static void f();
    void f();
};

class empty_too : public empty {};
ですが、クラスまたはそのベースクラスに が まれている 、クラスはempty classではありません. 、 を むクラスにはvptrがあるため、データメンバーが されています. 
が ベースクラスである も です. に、 クラスは ベースクラスの オブジェクトを すポインタを とします.
のクラスの 、そのサイズは0ではありません.0の 、2つのオブジェクトは じアドレスを っているため、2つのオブジェクトを にアドレスで することはできません. 、1つの のクラスのサイズは、コンパイラによって1または4である があります.
のクラスメンバーサブオブジェクトを むクラスの 、empty base class optimizationと ばれる を するコンパイラがあるため、 の を できます.
では、この について しています.
10/5 Derived classes
A base class subobject may be of zero size (clause 9); however, two subobjects that have the same class type and that belong to the same most derived object must not be allocated at the same address (5.10).
ベースクラスのサブオブジェクトは、サイズが0であってもよいが、2つの じタイプのサブオブジェクトが じアドレスに り てられないことに されている.だからテクニックは のクラスから することで の を することです.
class empty1 {};
class empty2 {};

class non_empty1
{
public:
    empty1 o1;
    empty2 o2;
};

class non_empty2
    : public empty1
    , public empty2
{};
ここでempty 1,2は のクラスで、 を じて、non_Empty 2の きさはやはり1です.でもnon_empty 1の きさは2です.
コードでは、ユーザーが したクラスに が まれているかどうか からないため、 はインタフェースに を える があります. が まれている 、 たちのクラスと じ の がある があります.これにより、 たちの は されます.この を するには、 のクラスから するのではなく、 クラスを し、この に のクラスを させることで、 を たちの クラスに することができます.この クラスのオブジェクトをメンバーとして します.
class empty {};
class foo : public empty {}; // not always correct

class foo
{
    class bar : public empty {};
    // ok, the interface of foo is not affected by the inheritance from empty;
};
stlでは、 オブジェクトが に され、 くの オブジェクトが であり、これらの オブジェクトが に されると、 の をもたらす(なぜ されるのか、 して、ハハ).
「C++template metaprogramming」には、 な f(g(x))を するクラスがある.
template<typename R, typename F, typename G>
class composed_fg
{
public:
    composed_fg(const F& f, const G& g)
        : f(f)
        , g(g)
    {}

    template<typename T>
    R operator ()(const T& t) const
    {
        return f(g(t));
    }
private:
    F f;
    G g;
};
ここでfまたはgが のクラスであれば、 の をもたらし、コンパイラによって なり、composed_fgは 32ビットプラットフォームで8バイトを する があります.しかし,fまたはgに クラスがある に なる を する クラス を った. 
boost.compressed_pairは されたstd.pairを し、boost.を します.compressed_pairの .
compressed_pairはT 1,T 2のタイプによって なる を し,6つのケースがある.
T1 == T2
T1 empty
T2 empty
false
false
false
false
true
false
false
false
true
false
true
true
true
false
false
true
true
true
ここで,T 1=T 2を するのは,C++が じ ベースクラスを2つ つことを さないためである.
template <class T1, class T2>
class compressed_pair_imp<T1, T2, 0>
{
public:
    typedef T1                                                 first_type;
    typedef T2                                                 second_type;
    typedef typename call_traits<first_type>::param_type       first_param_type;
    typedef typename call_traits<second_type>::param_type      second_param_type;
    typedef typename call_traits<first_type>::reference        first_reference;
    typedef typename call_traits<second_type>::reference       second_reference;
    typedef typename call_traits<first_type>::const_reference  first_const_reference;
    typedef typename call_traits<second_type>::const_reference second_const_reference;

    compressed_pair_imp() {}

    compressed_pair_imp(first_param_type x, second_param_type y)
        : first_(x), second_(y) {}

    compressed_pair_imp(first_param_type x)
        : first_(x) {}

    compressed_pair_imp(second_param_type y)
        : second_(y) {}
    // ...
    void swap(::boost::compressed_pair<T1, T2>& y)
    {
        cp_swap(first_, y.first());
        cp_swap(second_, y.second());
    }
private:
    first_type first_;
    second_type second_;
};
これはT 1もT 2も ではない であり,ここでは にオブジェクトに2つのメンバオブジェクトが されているだけである.そのうちの1つが の を てみましょう.
template <class T1, class T2>
class compressed_pair_imp<T1, T2, 1>
    : protected ::boost::remove_cv<T1>::type
{
public:
    typedef T1                                                 first_type;
    typedef T2                                                 second_type;
    typedef typename call_traits<first_type>::param_type       first_param_type;
    typedef typename call_traits<second_type>::param_type      second_param_type;
    typedef typename call_traits<first_type>::reference        first_reference;
    typedef typename call_traits<second_type>::reference       second_reference;
    typedef typename call_traits<first_type>::const_reference  first_const_reference;
    typedef typename call_traits<second_type>::const_reference second_const_reference;

    compressed_pair_imp() {}

    compressed_pair_imp(first_param_type x, second_param_type y)
        : first_type(x), second_(y) {}

    compressed_pair_imp(first_param_type x)
        : first_type(x) {}

    compressed_pair_imp(second_param_type y)
        : second_(y) {}

    void swap(::boost::compressed_pair<T1,T2>& y)
    {
        // no need to swap empty base class:
        cp_swap(second_, y.second());
    }
private:
    second_type second_;
};

ここでT 1は 、compressed_pairはT 1から き いだが、T 2はメンバーとして された.もう つの はswapでsecondのみが されていることであり,T 1サブオブジェクトが であるためswapには がないことは らかである. の は ているので、 でboostのソースコードを ることができます.

Side Note


VCではEmpty base classを に する があり、2つの じタイプのベースクラスサブオブジェクトの 、g++では2バイトサイズのオブジェクトが され、VCでは1バイトのサイズにすぎない.

References


[1] The "Empty Member"C++ Optimization [2] Empty Base Class or Structure Assignment Operator May Corrupt Data [3] Understanding the Empty Base Optimization [4] 《C++ template metaprogramming》 [5] Why is the size of an empty class not zero?