当前位置:编程学习 > C/C++ >>

空基类优化EBO之深度探索

 一、EBO的背景
   我们知道一个空的类,也就是其内部没有非静态数据成员,没有虚指针(包括指向虚函数表和虚基类子对象的指针),它的大小通常为1,当然在某些对齐要求严格系统上可能是另一个数(通常是4),如果空类被继承,那么派生类的大小会怎么样呢?一个支持C++标准和EBO的编译器对此会进行空基类的优化,也就是不给空的基类子对象分配空间,换句话说,空基类子对象的地址和其派生类实例的地址是相同的。从编译器实现的角度来看,需要考虑继承时的不同情况,下图中P表示父类,C表示子类,圆形表示空类,矩形表示非空类。单继承EBO情况如下图所示 

\

   EBO-1反映的是空类派生自空基类,EBO-2反映的是非空类派生自空基类,EBO-3、EBO-4反映的是在继承链中,对空基类的优化能不能传递到后代中。多继承EBO如下图所示

\
   EBO-5反映的是空类派生自两个空基类,EBO-6反映的是非空类派生自两个空基类,EBO-6反映的是空类派生自一个非空基类和一个空基类,EBO-7反映的是非空类派生自一个非空基类和一个空基类。以上8种情况,不论是单继承还是多继承,一个完全支持EBO的编译器就应该能把空基类部分都优化掉。

   二、EBO的应用
   由于空基类优化技术节省了对象不必要的空间,提高了运行效率,因此成为某些强大技术的基石,基于类型定义类如stl中的binary_function、unary_function、iterator、iterator_traits的实现复用;基于策略类如内存管理、多线程安全同步的实现复用。当某个类存在空类类型的数据成员时,也可考虑借助EBO优化对象布局,代码描述如下
1template<typename T1,typename T2>
2class EBO
3{
4private:
5    T1 m_t1;
6    T2 m_t2;
7};
   当T1和T2为空类时,可以改进如下

1template<typename T1,typename T2>
2class EBO : T1, T2
3{
4};
   进一步扩展考虑,如果T1或T2为非类类型,如基本内建类型、函数指针等;或T1和T2类型相同时,则直接继承它们会导致编译错误,怎么办呢?这时可以添加一个中间层来解决,代码如下
 1template<typename T1,typename T2,bool isSame,bool isFirstEmpty,bool isSecondEmpty>
 2class EBO_IMPL;
 3
 4template<typename T1,typename T2>
 5class EBO_IMPL<T1,T2,false,false,false>
 6{
 7    T1 m_t1;
 8    T2 m_t2;
 9};
10
11template<typename T1,typename T2>
12class EBO_IMPL<T1,T2,false,true,true> : T1,T2
13{
14};
15
16template<typename T1,typename T2>
17class EBO_IMPL<T1,T2,false,true,false> : T1
18{
19    T2 m_t2;
20};
21
22template<typename T1,typename T2>
23class EBO_IMPL<T1,T2,false,false,true> : T2
24{
25    T1 m_t1;
26};
27
28template<typename T1,typename T2>
29class EBO_IMPL<T1,T2,true,false,false>
30{
31    T1 m_t1;
32    T2 m_t2;
33};
34
35template<typename T1,typename T2>
36class EBO_IMPL<T1,T2,true,true,true> : T1
37{
38    T2 m_t2;
39};
40
41template<typename T1,typename T2>
42class EBO : EBO_IMPL<T1,T2,boost::is_same<T1,T2>::value,boost::is_empty<T1>::value,boost::is_empty<T2>::value>
43{
44};
   为了简便实现,上面代码直接使用了boost中的is_same,is_empty元函数来判断类型的属性,实际上boost中已经实现了EBO的选择运用工具即compressed_pair类模板,研究其源码可发现,该工具充分考虑到了T1和T2实际类型的各种情况,is_empty的判断是运用sizeof来比较类型大小确定的。替换compressed_pair后,代码如下
1template<typename T1,typename T2>
2class EBO: boost::compressed_pair<T1,T2>
3{
4};

补充:软件开发 , C语言 ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,