I was reading about Empty Base Optimization(EBO). While reading, the following questions popped up in my mind:
What is the point of using Empty class as base class when it contributes nothing to the derived classes (neither functionality-wise, nor data-wise)?
In this article, I read this:
//S is empty
class struct T : S
{
int x;
};[...]
Notice that we didn’t lose any data or code accuracy: when you create a standalone object of type S, the object’s size is still 1 (or more) as before; only when S is used as base class of another class does its memory footprint shrink to zero. To realize the impact of this saving, imagine a vector that contains 125,000 objects. The EBO alone saves half a megabyte of memory!
Does it mean that if we don't use "S" as base class of "T", we would necessarily consume double of megabyte of memory? I think, the article compares two different scenarios which I don't think is correct.
I would like to know a real scenario when EBO can proven to be useful.(means, in the same scenario, we would necessarily be at loss IF we don't use EBO!).
The whole point is that an empty class has non-zero size, but when derived or deriving it can have zero size, then I'm NOT asking that, as I know that already. My question is, why would anyone derive his class from an empty class in the first place? Even if he doesn't derive and simply writes his class (without any empty base), is he at loss in ANY way?
Empty base optimization (EBO)Allows the size of an empty base subobject to be zero.
An empty class could be used as a "token" defining something unique; in certain patterns, you want an implementation-agnostic representation of a unique instance, which has no value to the developer other than its uniqueness.
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.
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.
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With