对于 sizeof(class_name) 值的讨论(2)

之前我曾有一篇博客讨论过 sizeof 一个类的值的问题, 但只是在讨论一个孤立的类, 没有考虑到 derived 的问题, 在此补充更多的情况。
考察以下代码:

class X{};
class Y: public virtual X{};
class Z: public virtual X{};
class A: public Y, public Z{};

问题: sizeof() X, Y, Z, A 的值分别是多少呢?
class X 虽然是空的, 但是 sizeof(X) == 1, 这是因为 class X 内有一个被编译器安插进去的 char, 这使得两个 class X object 得以在内存中配置独一无二的地址。
而 sizeof(Y) == sizeof(Z) == 8 则需要考虑三个因素:
1. 语言本身所造成的额外负担(overload) 当语言支持 virtual base classes 时, 就会导致一些额外负担。 在 derived class 中, 则反映在某种形式的指针上, 它可能指向 virtual base class subobject 或者指向一个相关的表格, 表格中存放的可能是 virtual base class subobject 的地址, 也可能是其偏移量。这就涉及到具体机器上指针的大小。


2. 编译器对特殊情况所做出的优化处理。 virtual base class X subobject 的 1 bytes 大小也可能出现在 class Y 和 Z 上。传统上它被放在 derived class 的固定部分的尾端。 而某些编译器会对 empty virtual base class 提供特殊之处支持。


3. 对齐。 传统上, class Y 和 Z 的大小截至目前是 5 bytes。 但是在大部分机器上, 群聚的结构体大小会受到对齐的限制, 使他们有效的在内存中被存取。 vptr 的大小是 4 bytes, 因此 class Y 和 Z 必须填补 3 bytes。 最终得到的结果就是 8 bytes。

X, Y, Z 的关系如下图:

 

因此, sizeof(Y) 和 sizeof(Z) 的值就是 8 bytes 了吗?
不, 一个 empty virtual base class 已经成为了 C++OO 设计的一个特有术语了。 它提供一个 virtual interface, 没有定义任何数据。一些编译器对此提供了特殊处理, 在这个策略之下, 一个 empty virtual base class 被视为 derived class object 最开始的一部分, 也就是说, 并没有花费任何的额外空间。 这就节省了上述第二点的 1 bytes, 又从而变相节省了 3 bytes (因为既然 empty virtual base class 被视为了 derived class 的 member, 那么就不需要再安插一个 char, 巧合的是, 也不用因此而对齐了) 因而在这种情况下, sizeof(Y) == sizeof(Z) == 4;
好了, 最后一个, sizeof(A) 的值是多少呢? 如果 Y 和 Z 不是 virtual derived class X, 那么理论上 sizeof(A) == 16. 但是, 因为恰恰是 virtual derived, 所以 sizeof(A) 的值要从以下几点考虑:


1. 被大家共享的唯一一个 class X 实体, 大小为 1 byte。


2. Base class Y 的大小, 减去因 virtual base class X 而配置的大小, 结果是 4 bytes。 Base class Z 的算法亦同 。加起来是 8 bytes。


3. class A 自己的大小是 0 byte.


4. class A 的对对齐数量。前述三项总和, 表示调整前的大小是 9 bytes, 但是 class A 必须调至 4 bytes 的边界, 所以要填补 3 bytes。 结果是 12 bytes。

但是同样, 一旦我们考虑到那种对 empty virtual base class 做了处理的编译器, 前述的 class X 实体的那 1 byte 将会被拿掉, 于是又再省下了 3 bytes 的填补额, 于是在此种编译器的环境下, sizeof(A) == 8;

我自己对代码在 64 bit 的 windows8.1 系统的 msvc 的编译器下实验的结果是:
sizeof(X) == 1;

sizeof(Y) == sizeof(Z) == 4;

sizeof(A) == 8;

posted @ 2014-11-17 19:48  wu_overflow  阅读(224)  评论(0编辑  收藏  举报