首页 > C++编程 > 空白基类最优化 The Empty Base Class Optimization (EBCO)

空白基类最优化 The Empty Base Class Optimization (EBCO)

Basic Information

C++ classes are often “empty,” which means that their internal representation does not require any bits of memory at run time. This is the case typically for classes that contain only type members, nonvirtual function members, and static data members. Nonstatic data members, virtual functions, and virtual base classes, on the other hand, do require some memory at run time.

Even empty classes, however, have nonzero size. Try the following program if you’d like to verify this:

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
using namespace std;
 
class EmptyClass
{
};
 
int main(int argc, char **argv)
{
	cout << "sizeof(EmptyClass):" << sizeof(EmptyClass) << endl;
	return 0;
}

For many platforms, this program will print 1 as size of EmptyClass. A few systems impose more strict alignment requirements on class types and may print another small integer (typically, 4).

Layout Principles

The designers of C++ had various reasons to avoid zero-size classes. For example, an array of zero-size classes would presumably have size zero too, but then the usual properties of pointer arithmetic would not apply anymore. For example, let’s assume ZeroSizedT is a zero-size type:

1
2
3
ZeroSizeT z[10];
//...
&z[i] - &z[j]	// 计算地址之间的差值

Normally, the difference in the previous example is obtained by dividing the number of bytes between the two addresses by the size of the type to which it is pointing, but when that size is zero this is clearly not satisfactory.

However, even though there are no zero-size types in C++, the C++ standard does specify that when an empty class is used as a base class, no space needs to be allocated for it provided that it does not cause it to be allocated to the same address as another object or subobject of the same type. Let’s look at some examples to clarify what this so-called empty base class optimization (or EBCO) means in practice. Consider the following program:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
using namespace std;
 
class Empty
{
    typedef int Int;
}; 
 
class EmptyTwo : public Empty 
{ 
}; 
 
class EmptyThree : public EmptyTwo 
{ 
}; 
 
int main() 
{ 
    cout << "sizeof(Empty):      " << sizeof(Empty) << endl;
    cout << "sizeof(EmptyTwo):   " << sizeof(EmptyTwo) << endl;
    cout << "sizeof(EmptyThree): " << sizeof(EmptyThree) << endl;
 
    return 0;
}

If your compiler implements the empty base optimization, it will print the same size for every class, but none of these classes has size zero. This means that within class EmptyToo, the class Empty is not given any space. Note also that an empty class with optimized empty bases (and no other bases) is also empty. This explains why class EmptyThree can also have the same size as class Empty. If your compiler does not implement the empty base optimization, it will print different sizes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
using namespace std;
 
class Empty 
{
    typedef int Int;
}; 
 
class EmptyTwo : public Empty
{
}; 
 
class NonEmpty : public Empty, public EmptyTwo
{
}; 
 
int main() 
{ 
    cout << "sizeof(Empty):    " << sizeof(Empty) << endl;
    cout << "sizeof(EmptyTwo): " << sizeof(EmptyTwo) << endl;
    cout << "sizeof(NonEmpty): " << sizeof(NonEmpty) << endl;
 
    return 0;
}

It may come as a surprise that class NonEmpty is not an empty class After all, it does not have any members and neither do its base classes. However, the base classes Empty and EmptyToo of NonEmpty cannot be allocated to the same address because this would cause the base class Empty of EmptyToo to end up at the same address as the base class Empty of class NonEmpty. In other words, two subobjects of the same type would end up at the same offset, and this is not permitted by the object layout rules of C++. It may be conceivable to decide that one of the Empty base subobjects is placed at offset “0 bytes” and the other at offset “1 byte,” but the complete NonEmpty object still cannot have a size of one byte because in an array of two NonEmpty objects, an Empty subobject of the first element cannot end up at the same address as an Empty subobject of the second element .

The rationale for the constraint on empty base optimization stems from the fact that it is desirable to be able to compare whether two pointers point to the same object. Because pointers are nearly always internally represented as just addresses, we must ensure that two different addresses (that is, pointer values) correspond to two different objects.

The constraint may not seem very significant. However, in practice, it is often encountered because many classes tend to inherit from a small set of empty classes that define some common typedefs. When two subobjects of such classes are used in the same complete object, the optimization is inhibited.


觉得文章还不错?点击此处对作者进行打赏!


本文地址: 程序人生 >> 空白基类最优化 The Empty Base Class Optimization (EBCO)
作者:代码疯子(Wins0n) 本站内容如无声明均属原创,转载请保留作者信息与原文链接,谢谢!


更多



分类: C++编程 标签: , ,
  1. 本文目前尚无任何评论.