1, why the size of the class is not allowed in C + + is 0
Class Zerosizet {}; Zerosizet Z[10];&z[i]-&z[j]; is usually obtained by dividing the number of bytes between two addresses by the type size, while the type size is 0 will be problematic
2, why sometimes more than one class composition instance occupies the same space
Class empty{};class emptytoo:public empty{};class emptythree:public emptytoo{};sizeof (Empty): 1sizeof (EmptyToo): 1sizeof (emptythree): 1
Empty base class Optimization: You do not need to allocate space to a different object or sub-object of the same type as long as it is not assigned to the same address
1, why the size of the class is not allowed in C + + is 0
Class Zerosizet {}; Zerosizet Z[10];&z[i]-&z[j]; is usually obtained by dividing the number of bytes between two addresses by the type size, while the type size is 0 will be problematic
2, why sometimes more than one class composition instance occupies the same space
Class empty{};class emptytoo:public empty{};class emptythree:public emptytoo{};sizeof (Empty): 1sizeof (EmptyToo): 1sizeof (emptythree): 1
Empty base class Optimization: You do not need to allocate space to a different object or sub-object of the same type as long as it is not assigned to the same address.
3, for the empty base class optimization, how to understand the precondition "as long as no other object or sub-object of the same type is assigned to the same address", and why
Class empty{};class emptytoo:public empty{};class emptythree:public empty, public emptytoo{};sizeof (empty): 1sizeo F (Emptytoo): 1sizeof (emptythree): 2
The Noempty base class empty and Emptytoo cannot be allocated in the same address space, and the C + + memory layout does not allow the same type of sub-object offsets.
The fundamental reason for limiting the space base class optimization is that we need to be able to compare whether two pointers point to the same object. Since pointers are almost always internally represented by an address, it is important to ensure that two different addresses correspond to two different objects.
In more detail: http://www.programlife.net/the-empty-base-class-optimization.html
Report:
Application of space-based optimization: In the p_435 of the e_cn of the C + + Templates, the combinatorial relation of the function object is changed into the inheritance relation by using the characteristic of the empty base class optimization.
What's empty class and why worth optimization
Empty class, as its name implies, is null, such as
[CPP]View Plaincopyprint?
- class Empty {};
Here empty is obviously an empty class, and none of the members are. However, an empty class is not limited to this form, and it can be an empty class for only member functions and without non-static data MembeR.
[CPP]View Plaincopyprint?
- Class empty
- {
- Public
- static void f ();
- void f ();
- };
- Class Empty_too: Public Empty {};
However, it is important to note that if a class or his base class contains virtual functions, then the class is not empty class, because usually a class containing virtual functions has a vptr, so there is a data member, although it is hidden.
The same is true for a parent class that is a virtual base class, because a generic subclass requires a pointer to a child object of the virtual base class.
For an empty class, its size is not 0, because if it is 0, then two objects will have the same address, so it is not easy to use the address to distinguish between two objects. Typically, an empty class may be 1 or 4, depending on the compiler.
If a class contains an empty class member sub-object, then this creates a waste of space, which can be avoided because some compilers implement an optimization called the empty base class optimization.
This optimization is mentioned in the standard:
10/5 Derived Classes
A base class Subobject may be of zero size (clause 9); However, subobjects that has the same class type and that belong to the same most derived object must not being allocate D at the same address (5.10).
The base class sub-object can be a size of 0, but the limit is that two sub-objects of the same type cannot be assigned to the same address. So the trick is to achieve some optimization by inheriting from an empty class.
[CPP]View Plaincopyprint?
- class empty1 {};
- class empty2 {};
-
- class non_empty1
- {
- public:
- empty1 o1;
- empty2 o2;
- };
-
- class non_empty2
- : PUBLIC EMPTY1  
- , public empty2
- {};
Here empty1,2 is empty class, through inheritance, the size of Non_empty2 is still 1. But the size of the non_empty1 is 2.
It is important to note that inheritance can have an impact on the interface, because in generic code you do not know whether a user-passed class contains a virtual function, and if it contains a virtual function, then there may be a virtual function that has exactly the same name as our class, so that our function is falsified.
To solve this problem, you can not inherit from the empty class directly, but instead create an intermediate class and let the class inherit the empty class, which restricts the impact to our intermediate class. and save the object of the intermediate class as a member.
[CPP]View Plaincopyprint?
- 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;
- };
In STL, a large number of function objects are used, and there are many function objects that are empty, and it can be wasteful to store these function objects in large quantities (why store them?). Imagine, haha).
There is an example in C + + template metaprogramming: There is a class that implements a simple compound function f (g (x))
[CPP]View Plaincopyprint?
- 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;
- };
If f or G is an empty class, it can create a waste of space, depending on the compiler, COMPOSED_FG may occupy up to 8 bytes on the 32-bit platform. But we do an empty base class optimization, when there are empty base classes in F or G, we choose different implementations.
Boost.compressed_pair has implemented an optimized std.pair, let's analyze Boost.compressed_pair's implementation.
Compressed_pair according to the type of T1, T2, to choose different implementations, there are 6 kinds of situations
t1 = T2 |
t1 empty |
t2 empty |
false |
false |
false |
false |
true |
false |
false |
false |
true |
f Alse |
true |
true |
true |
false |
false |
true |
true |
true |
This distinguishes t1==t2 because C + + does not allow 2 of the same direct base class.
What isEmptyclassand why worth Optimizationempty class, as its name implies, is an empty class, such as [CPP] View Plaincopyprint?classempty {}; Here empty is obviously an empty class, and none of the members are. But empty classes are not limited to this form, for only member functions, and no non-Staticthe data member class, or it can be an empty class. [CPP] View Plaincopyprint?classEmpty { Public: Static voidf (); voidf (); }; classEmpty_too: Publicempty {}; But one thing to note is that if a class or his base class contains virtual functions, then the class is not emptyclass, because usually a class containing virtual functions has a vptr, so there is a data member, although it is hidden. The same is true for a parent class that is a virtual base class, because a generic subclass requires a pointer to a child object of the virtual base class. For an empty class, its size is not 0, because if it is 0, then two objects will have the same address, so it is not easy to use the address to distinguish between two objects. Typically, an empty class may be 1 or 4, depending on the compiler. If a class, which contains empty class member sub-objects, then this will cause a certain amount of space waste, and this waste can be avoided, because some compilers implement a kind of called emptyBase classoptimization of optimization. This optimization is mentioned in the standard:Ten/5Derived ClassesaBase classSubobject May is of zero size (clause9); However, subobjects that has the sameclassType and that belong to the same most derivedObjectMust not being allocated at the same address (5.10). The base class sub-object can be a size of 0, but the limit is that two sub-objects of the same type cannot be assigned to the same address. So the trick is to achieve some optimization by inheriting from an empty class. [CPP] View Plaincopyprint?classempty1 {}; classEmpty2 {}; classNon_empty1 { Public: Empty1 O1; Empty2 O2; }; classNon_empty2: PublicEmpty1, PublicEmpty2 {}; Here empty1,2 is empty class, through inheritance, the size of Non_empty2 is still 1. But the size of the non_empty1 is 2. It is important to note that inheritance can have an impact on the interface, because in generic code you do not know whether a user-passed class contains a virtual function, and if it contains a virtual function, then there may be a virtual function that has exactly the same name as our class, so that our function is falsified. To solve this problem, you can not inherit from the empty class directly, but instead create an intermediate class and let the class inherit the empty class, which restricts the impact to our intermediate class. and save the object of the intermediate class as a member. [CPP] View Plaincopyprint?classempty {}; classFoo: PublicEmpty {};//Not always correct classFoo {classBar: Publicempty {}; //OK, the interface of Foo is not affected by the inheritance from empty; }; In STL, a large number of function objects are used, and there are many function objects that are empty, and it can be wasteful to store these function objects in large quantities (why store them?). Imagine, haha). In the C++There is an example in template metaprogramming: There is a class that implements a simple compound function f (g (x)) [CPP] View Plaincopyprint?Template<typename R, TypeName F, TypeName g>classCOMPOSED_FG { Public: COMPOSED_FG (Constf& F,Constg&g): F (f), g (g) {} template<typename t>Roperator()(Constt& t)Const { returnF (g (t)); } Private: F F; g G; }; If f or G is an empty class, then it will cause a waste of space, depending on the compiler, COMPOSED_FG may-the bit platform occupies 8 bytes. But we do an empty base class optimization, when there are empty base classes in F or G, we choose different implementations. Boost.compressed_pair has implemented an optimized std.pair, let's analyze Boost.compressed_pair's implementation. Compressed_pair according to the type of T1, T2, to choose different implementations, there are 6 kinds of situations T1==T2 T1 empty T2 emptyfalse false falsefalse true falsefalse false truefalse true truetrue false falsetrue true truewhich distinguishes T1==t2 is because C + + does not allow 2 of the same direct base class.
This is a case where both T1 and T2 are not empty, and this is simply a simple way to save 2 member objects in the object. Let's take a look at one of the empty cases.
Template <classT1,classT2>classCOMPRESSED_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>::p aram_type first_param_type; typedef typename Call_traits<second_type>::p aram_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) {}voidSwap (::boost::compressed_pair<t1,t2>&y) {//no need to swap empty base class:Cp_swap (Second_, Y.second ()); }Private: Second_type second_;};
Here T1 is empty, Compressed_pair inherited from T1, but T2 is still saved as a member. There is also a change in swap, which only operates on second, and it is clear that swap is meaningless because the T1 sub-object is empty.
Other things are similar, so you can see the source of the boost yourself.
Side Note
In VC there is an over-optimization of the empty base class, for 2 of the same type base class sub-objects, in g++, a 2-byte-size object is generated, and the VC is only 1 bytes in size.
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 a empty class not zero?
Reference: http://blog.csdn.net/seizef/article/details/6168721
Http://www.bubuko.com/infodetail-479676.html
Http://www.cppblog.com/qinqing1984/archive/2011/07/10/150584.aspx
Empty base class optimization empty optimization