lei*_* hu 4 c++ memory inheritance struct sizeof
我写了三个类:A、B和C。A没有成员变量,B有一个整型类型的成员变量,C有一个类型为 的成员变量B,如下所示:
class A {
public:
};
class B : public A{
private:
int value_;
};
class C : public A{
private:
B a;
};
Run Code Online (Sandbox Code Playgroud)
让我惊讶的是,sizeof(C)正如预期的那样,是 8 而不是 4 sizeof(B)。我曾考虑过这可能是由于填充造成的,但是当我删除C继承自A或B继承自时A,sizeof(C)如预期的那样变成了 4。
当使用 GCC 和 Clang 时,我在 64 位机器上观察到相同的行为。
我想知道为什么编译器在编译时会额外增加4个字节的存储开销C。
use*_*522 10
中有两个子A对象C:直接A基类子对象和成员子对象A的基类子对象B。
该标准要求这两个对象不具有相同的地址,因为它们具有相同的类型和重叠的生存期,并且因为一个对象不嵌套在另一个对象中。(参见[intro.object]/9)
因此,不可能对类进行布局,C以便直接A子对象和B成员子对象都分配在偏移量 0 处。
假设分配按顺序从直接A基类子对象的偏移量 0 处开始,那么也尊重对齐要求的最佳分配策略是将成员子对象放在偏移量 4 处,这是和B的对齐要求。因此总大小至少为 8。intB
从技术上讲,我认为标准也允许(忽略本问题末尾提出的问题)将B成员子对象布局在偏移处0,并将A成员子对象布局在除 之外的任何偏移处0,因为A基类子对象是零的子对象可能与部分子对象重叠的大小int。我认为也没有强制基类子对象的地址小于或等于B成员子对象的地址的排序要求。有了这样的选择,sizeof(C) == 4就有可能。但这将是一个令人惊讶的布局。
到目前为止,关于标准对布局的要求,但标准并没有指定编译器实际选择的具体布局。相反,它将由所使用的 C++-ABI 决定,如果您在 Linux 系统上使用 GCC 或 Clang 进行编译,则为Itanium C++ ABI 。此 ABI 使用的分配算法在此处指定(对于出于布局目的而不是 POD 的类,但事实C并非如此)。您可以在那里看到特殊情况:
将 D 放置在此偏移处,除非这样做会导致同一类型的两个组件(直接或间接)具有相同的偏移量。[...]
MSVC,遵循它自己的 C++-ABI,说sizeof(C) == 4并且通过我的测试似乎给出了直接A基类子对象以及B成员子对象 offset 0,使用不符合上述要求的不同分配策略。
不幸的是,该标准存在缺陷,导致无法正确布局C。
一方面,如上所示,B必须放置在与直接A基子对象的偏移处,但是根据标准中的当前定义,它C是一个标准布局类,这意味着根据[basic.compound]/4,直接基子对象和A基类子对象以及B作为 的第一个非静态成员的成员子对象C必须放置在与C对象相同的地址处,即偏移量 0 处。
这是标准中的一个缺陷,(我猜)可能会通过使其C不是标准布局来解决。那么 MSCV 的 ABI 将仍然不符合要求,但这也可能使针对缺陷采用该解决方案变得困难。
请参阅开放的CWG 问题 2736。