如果类包含基类的成员,编译器是否可以利用空基优化?

时间:2017-07-04 15:11:27

标签: c++ language-lawyer

考虑

struct base {};
struct child : base {};

众所周知,通过应用空基优化sizeof(child)可以为1。

然而,现在考虑

struct base {};
struct child : base {base b;};

编译器现在可以应用空基优化,还是sizeof(child)必须至少为2?

参考:http://en.cppreference.com/w/cpp/language/ebo

4 个答案:

答案 0 :(得分:18)

不,它不能。来自同一参考:

  

如果其中一个空基类,则禁止空基优化   也是第一个非静态数据类型的类型或基础   构件

因此sizeof(child) >= 2

答案 1 :(得分:15)

规则是相同类型的子对象不能在同一地址。这里有2个X个子对象,因此每个子对象必须位于不同的地址。

相同类型的对象不能共享相同的地址,因为C ++中对象的标识是其地址。如果相同类型的多个对象共享相同的地址,则它们是无法区分的。这就是最小完整对象大小为1的原因,因此数组中的每个对象都有一个不同的地址。请参阅“§C++对象模型[intro.object]”:

  

对象是存储区域。

     

...

     

对象可以包含其他对象,称为子对象。子对象可以是成员子对象(9.2),基类子对象(子句10)或数组元素。不是任何其他对象的子对象的对象是   称为完整对象。

     

...

     

除非它是位字段(9.6),否则最派生的对象应具有非零大小并且应占用一个或多个存储字节。基类子对象的大小可以为零。

     

...

     

除非对象是零字段或零大小的基类子对象,否则该对象的地址是它占用的第一个字节的地址。如果一个是另一个的子对象,或者如果至少一个是零大小的基类子对象并且它们是不同类型的,则不是位字段的两个对象可以具有相同的地址;否则,他们应有不同的地址。

这就是为什么,例如,boost::noncopyable可以增加一个类大小,如果一个人在不知不觉中通过空基类间接地继承它。例如。在:

struct A : boost::noncopyable {};
struct B : boost::noncopyable {};
struct C : boost::noncopyable {};
struct D : A, B, C {};

sizeof(D) == 3因为有三个不同的boost::noncopyable子主题。如果删除boost::noncopyable的派生,则sizeof(D) == 1

答案 2 :(得分:14)

C ++中的对象需要具有唯一的“身份”。来自[intro.object] / 8(N4659):

  

两个对象ab具有重叠的生命周期而非位字段,如果一个嵌套在另一个中,则可能具有相同的地址,或者如果至少有一个是0的基类子对象尺寸和它们是不同类型的;否则,他们有不同的地址。

基类子对象和成员子对象是单独的对象;两者都没有“嵌套”在另一个之内。因此,如果它们属于同一类型,则它们必须具有单独的地址。

请注意,这会以递归方式扩展。请考虑以下事项:

struct eb1 {};

struct eb2 : eb1 {};
struct not_empty(eb1 a;};

struct derived : eb2 {not_empty b;};

由于C ++的唯一标识规则,derived::eb2::eb1 必须derived::b::a具有不同的地址。因此,编译器不能derived上使用EBO。

答案 3 :(得分:6)

我会在另一个更基本的引语中加入

[intro.object]

  

如果一个嵌套在另一个中,则两个具有重叠生命周期且不是位字段的对象a和b可以具有相同的地址,或者如果至少一个是零大小的基类子对象并且它们具有不同类型,则它们可以具有相同的地址。否则,他们有不同的地址。

由于b不是继承的base的子对象,因此它们必须具有不同的地址。