Empty class and optimization
6539 ワード
What is empty class and why worth optimization
Empty classはその名の通り空のクラスです.例えば
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?