【问题标题】:How sizeof a not-polymorphic C++ class can be larger than the summed sizeof of its members?非多态 C++ 类的 sizeof 可以大于其成员的总 sizeof 多少?
【发布时间】:2022-01-09 08:10:03
【问题描述】:

在以下示例中,结构 E 继承结构 CD,并且没有其他数据成员:

struct A{};
struct B{};
struct C : A, B {};
struct D : A, B {};
struct E : C, D {};

int main() {
    static_assert(sizeof(C) == 1);
    static_assert(sizeof(D) == 1);
    //static_assert(sizeof(E) == 2); // in Clang and GCC
    static_assert(sizeof(E) == 3); //in MSVC
}

在我测试过的所有编译器中,sizeof(C)==1sizeof(D)==1,并且仅在 MSVC 中 sizeof(E)==3 超过其父/成员的总大小,演示:https://gcc.godbolt.org/z/aEK7rjKcW

其实我希望能找到sizeof(E) <= sizeof(C)+sizeof(D)(在空基优化的情况下更少)。而且这里几乎没有任何填充,否则sizeof(E) 将是 2 或 4。

E 中的额外空间 (sizeof(E)-sizeof(C)-sizeof(D) == 1) 的用途是什么?

【问题讨论】:

  • 由于EBO,我实际上对 MSVC 的输出感到惊讶
  • 您创建了一个“钻石继承”形状。 IE。基类 A 和 B 在 E 中存在两次。除非您进行虚拟继承,否则您没有这样做。现在有趣的问题是,在那些编译中,sizeof(E) == 1,他们如何实现,E e; assert(static_cast<A*>(static_cast<C*>(&e)) !=static_cast<A*>(static_cast<D*>(&e)));
  • @BitTickler:我检查了偏移量——他们将 D 放在偏移量 1 处。gcc.godbolt.org/z/8r9384fK8
  • 好吧 - 也许我的断言不是块上最尖锐的断言......但你在 E 中有 2*A 和 2* B。所以你应该能够为它们获得 4 个不同的地址,是吗?
  • @BitTickler: AB 允许拥有相同的地址。不允许使用不同的As 和不同的Bs。

标签: c++ visual-studio sizeof


【解决方案1】:

首先,由于填充和对齐,它可能大于子对象的总和。但是,您可能已经意识到这一点,而这并不是您要问的。

要确定您的布局,您可以使用以下代码打印所有子对象的偏移量(及其类型的大小):

static E x;
int main() {
    E *e = &x;
    C *c = e;
    D *d = e;
    A *ca = c, *da = d;
    B *cb = c, *db = d;
#define OFF(p) printf(#p " %d %d\n",  (int)((char*)p - (char*)e), (int)sizeof(*p))
    OFF(e);
    OFF(c);
    OFF(ca);
    OFF(cb);
    OFF(d);
    OFF(da);
    OFF(db);
}

gcc/clang 的输出是:

e 0 2
c 0 1
ca 0 1
cb 0 1
d 1 1
da 1 1
db 1 1

MSVC 的输出是:

e 0 3
c 0 1
ca 0 1
cb 1 1
d 2 1
da 2 1
db 3 1

这表明 MSVC 实现 EBO 的方式与其他编译器不同。特别是,它不是将AB 放在C 中的同一地址和D 中的同一地址(就像其他编译器一样),而是将它们放在不同的偏移量处。然后,即使sizeof(C) == 1,当它是子对象时,它也会为它分配完整的两个字节。这样做很可能是为了避免 cb 将其他一些 B 与另一个子对象混淆,即使在这种情况下这不会成为问题。

【讨论】:

  • 谢谢。标准是否允许同时sizeof(C)==1C 字段之一cb 具有位移1?
  • @Fedor 我不知道;但是如果您尝试 memcpy 子对象,我可以看到它会如何导致问题。
猜你喜欢
  • 2011-12-19
  • 1970-01-01
  • 2011-04-23
  • 2017-08-30
  • 1970-01-01
  • 2010-10-08
  • 1970-01-01
  • 1970-01-01
  • 2011-07-27
相关资源
最近更新 更多