【C++】详解EBO:空基类优化

看侯捷的STL课时,常常听他抱怨STL 4.9版本的一些做法实在令人费解,听得多了难免有些疑问,难道真的是这样吗?怎么会逆历史潮流向后倒退呢?于是开始去找STL团队背后这样做的原因。

今天要总结的是C++中的EBO,又称“空基类优化”。

STL4.9里像vector_impl这种实现类会去继承一个空的allocator类,从面向对象的角度而言,public继承表达的是一种“is a"关系,private继承表达的是”has a“关系,如果这里vector_impl是私有继承还有情可原,但偏偏这里的继承是公有继承,这属实是有违常理,于是侯捷老师评价道:乱七八糟,舍近求远,何必如此!!

确实,从面向对象的角度而言,如此评价不无道理。但是,这种继承其实是C++中关于内存的一种优化,也就是EBO技术。让我们先做个实验:

C++空类的大小

定义一个空类A:

class A
{
};

对这个空类计算sizeof大小:

cout << sizeof(A) << endl;

运行结果:

1

这里我要问你一句:为什么不是0?

这是因为空类同样可以被实例化,为了让对象的实例能够相互区别,每个实例在内存中都有一个独一无二的地址,为了达到这个目的,编译器往往会给一个空类隐含的加一个字节,这样空类在实例化后在内存得到了独一无二的地址.所以上述大小为1;如果没有这一个字节的占位,那么空类就无所谓实例化了,因为实例化的过程就是在内存中分配一块地址,而你实例化两个对象出来,求其地址发现是同一个地址,这就说不通了。

组合

基于上面这个结论,我们再设计一个B类:

class A
{
};

class B
{
    A a{};
    int i{};
};

同样,对这个B类计算sizeof大小:

cout << sizeof(B) << endl;

运行结果:

8

这里你可能会说,a占一个字节,int占4个字节,那就是5个字节啊,为什么是8呢?

这是因为发生了字节对齐,将a原来只占1字节,进行扩充到4的倍数,最后就是8字节。但这并不是今天的重点。

现在B类通过组合,拥有了A类的所有功能,是个“has a”关系,于是,我们通过另一种手段——继承,也去实现这个功能:

class A
{
};

class B
{
    A a{};
    int i{};
};

class C :public A
{
    int i{};
};

看起来似乎很顺利,但是对这个C类计算sizeof大小时你可能会看出端倪:

B: 8
C: 4

而这便是所谓的空基类优化:当该空白类作为基类时,该类的大小就被优化为0了。

对比这两个发现,第二种通过继承方式来获得基类的功能,并没有产生额外大小的优化称之为EBO(空基类优化)。

今天这篇文章中的各种概念对于初学者来说是比较陌生的(不得不说C++的各种概念是真的多,不枉它活了20多年),不过我相信你们都能够理解,最后来回顾在本文中都学了什么吧。

首先是空基类优化其实在平时的开发中接触的比较少,最主要的用处还在是各个基础库中,能够用到std::vector只需要24个字节,EBO功不可没,并且其中还顺便普及一个Private继承的概念,这个在平时开发估计也接触的比较少,还是那句话C++中的特性基本没有多余的,你用不到并不代表它没用,它可能正在某个角落发挥着属于它的作用。

猜你喜欢

转载自blog.csdn.net/weixin_43717839/article/details/134351678
今日推荐