When do programmers use Empty Base Optimization (EBO)
Solution 1:
EBO is important in the context of policy based design, where you generally inherit privately from multiple policy classes. If we take the example of a thread safety policy, one could imagine the pseudo-code :
class MTSafePolicy
{
public:
void lock() { mutex_.lock(); }
void unlock() { mutex_.unlock(); }
private:
Mutex mutex_;
};
class MTUnsafePolicy
{
public:
void lock() { /* no-op */ }
void unlock() { /* no-op */ }
};
Given a policy based-design class such as :
template<class ThreadSafetyPolicy>
class Test : ThreadSafetyPolicy
{
/* ... */
};
Using the class with a MTUnsafePolicy
simply add no size overhead the class Test
: it's a perfect example of don't pay for what you don't use.
Solution 2:
EBO isn't really an optimization (at least not one that you do in the code). The whole point is that an empty class has non-zero size, but when derived or deriving it can have zero size.
This is the most usual result:
class A { };
class B { };
class C { };
class D : C { };
#include <iostream>
using namespace std;
int main()
{
cout << "sizeof(A) + sizeof(B) == " << sizeof(A)+sizeof(B) << endl;
cout << "sizeof(D) == " << sizeof(D) << endl;
return 0;
}
Output:
sizeof(A) + sizeof(B) == 2
sizeof(D) == 1
To the edit: The optimization is, that if you actually do derive (for example from a functor, or from a class that has only static members), the size of your class (that is deriving) won't increase by 1 (or more likely 4 or 8 due to padding bytes).
Solution 3:
The "Optimization" in the EBO means the case when you use base class can be optimized to use less memory than if you use a member of the same type. I.e. you compare
struct T : S
{
int x;
};
with
struct T
{
S s;
int x;
};
not with
struct T
{
int x;
};
If your question is why would you have an empty class at all (either as a member, or as a base), it is because you use its member functions. Empty means it has no data member, not that it does not have any members at all. Things like this are often done when programming with templates, where the base class is sometimes "empty" (no data members) and sometimes not.
Solution 4:
Its used when programmers want to expose some data to client without increasing the client class size. The empty class can contain enums and typedefs or some defines which the client can use.The most judicious way to use such a class it it to,inherit such a class privately. This will hide the data from outside and wil not increase your class size.
Solution 5:
There can be empty classes which do not have any member variables, but member functions (static
or non static
) which can act as utility classes, lets call this EmptyClass
. Now we can have a case where we want to create a class (let's call it SomeClass
) which have a containment kind of relation with EmptyClass
, but not 'is-a' relation. One way is to create a member object of type EmptyClass
in SomeClass
as follows:
class EmptyClass
{
public:
void someFun1();
static int someUtilityFun2();
};
//sizeof(EmptyClass) = 1
class SomeClass
{
private:
EmptyClass e;
int x;
};
//sizeof(SomeClass) = 8
Now due to some alignment requirements compilers may add padding to SomeClass
and its size is now 8 bytes. The better solution is to have a SomeClass
derive privately from EmptyClass
and in this way SomeClass
will have access to all member functions of EmptyClass
and won't increase the extra size by padding.
class SomeClass : private EmptyClass
{
private:
int x;
}
//sizeof(SomeClass) = 4