• 对于 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;

  • 相关阅读:
    iOS:网络检测
    WinJS:设置listView垂直滚动
    iOS:在AppDelegate中定义managed object context
    简笔画项目总结: ios绘图机制 & 实现记录笔迹功能
    CSS基础
    DOM小结
    iOS:view.frame
    WP:初探
    iOS:UIWebView scrollView 的分页滑动问题
    Mono for Android: 利用mono for android开发的第一个程序
  • 原文地址:https://www.cnblogs.com/wuOverflow/p/4104251.html
Copyright © 2020-2023  润新知