简体   繁体   English

非多态 C++ class 的大小可以大于其成员的总大小?

[英]How sizeof a not-polymorphic C++ class can be larger than the summed sizeof of its members?

In the following example struct E inherits structs C and D and has no other data members:在以下示例中,结构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
}

In all compilers I have tested, sizeof(C)==1 and sizeof(D)==1 , and only in MSVC sizeof(E)==3 so more than the summed size of its parents/members, demo: https://gcc.godbolt.org/z/aEK7rjKcW在我测试过的所有编译器中, sizeof(C)==1sizeof(D)==1 ,并且仅在 MSVC sizeof(E)==3中大于其父/成员的总大小,演示: https: //gcc.godbolt.org/z/aEK7rjKcW

Actually I expected to find sizeof(E) <= sizeof(C)+sizeof(D) (less in case empty base optimization).实际上我希望找到sizeof(E) <= sizeof(C)+sizeof(D) (在空基优化的情况下更少)。 And there is hardly any padding here, otherwise sizeof(E) would be 2 or 4.这里几乎没有任何填充,否则sizeof(E)将是 2 或 4。

What is the purpose of extra space ( sizeof(E)-sizeof(C)-sizeof(D) == 1 ) in E ? E 中额外空间( sizeof( E sizeof(E)-sizeof(C)-sizeof(D) == 1 )的目的是什么?

First, it can be larger than the sum of sub-objects due to padding and alignment.首先,由于填充和 alignment,它可能大于子对象的总和。 However, you're probably aware of that, and that's not what you are asking.但是,您可能已经意识到这一点,这不是您要问的。

To determine the layout in your case, you can print the offsets of all the sub-objects (and the sizes of their types) using the following code:要确定您的情况的布局,您可以使用以下代码打印所有子对象的偏移量(及其类型的大小):

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);
}

The output for gcc/clang is: gcc/clang 的 output 是:

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

The output for MSVC is: MSVC 的 output 是:

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

This indicates that the way MSVC implements EBO is different from other compilers.这表明 MSVC 实现 EBO 的方式与其他编译器不同。 In particular, instead of placing A and B at the same address within C , and at the same address within D (like other compilers do), it put them at different offsets.特别是,不是将AB放置在C中的相同地址,而是放置在D中的相同地址(就像其他编译器一样),而是将它们放置在不同的偏移量处。 Then, even though sizeof(C) == 1 , it allocates the full two bytes for it when it is a sub-object.然后,即使sizeof(C) == 1 ,当它是子对象时,它也会为它分配完整的两个字节。 This is most likely done so to avoid cb aliasing some other B from another sub-object, even though it wouldn't be a problem in this scenario.这样做很可能是为了避免cb将其他B与另一个子对象混淆,即使在这种情况下这不会成为问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM