如果基类是聚合,基类的尾部填充保证不会被派生类重用吗?



惊讶的c++程序员注意到只有当基类不是POD类型时才重用尾部填充,他们提出了许多问题。

例如,以下代码在x86-64 gcc (godbolt link)上运行:

struct A {
int a;
bool aa;
};
struct B : A {
bool b;
};
struct C : B {
bool c;
};
static_assert(sizeof(A) == 8);
static_assert(sizeof(B) == 12);
static_assert(sizeof(C) == 12);

这意味着字段c被放置到B的填充中,而字段b没有被放置到A的填充中。

链接的问题只解释了一个特定的ABI指定了这种布局,一个答案甚至说重用POD类型的尾部填充"打破了程序员所做的普遍假设",因此"基本上任何相同的编译器都不会进行尾部填充重用"。对于这样的类型。然而,这个解释并不令人满意,因为它实际上并不能保证任何事情。

标准是否保证POD类型的尾部填充不会被派生类重用?

作为一个聚合只涉及一件事:聚合初始化。与类型成员的布局无关。

由布局规则控制。A是标准布局,它是具有一定布局保证的类型的子集。类BC不是标准布局(或POD,或者你想叫它什么),所以在这些类型的布局中有更多的变化。

标准允许其他答案指定的任何实现。它们都是同等有效的

一个类型可以在它自己的子对象的非空基类中使用填充。这在一定程度上是因为对基类子对象(或任何其他可能重叠的子对象)执行类似memcpy的操作是明确禁止的:

对于普通可复制类型T…的任何对象(潜在重叠子对象除外)

最新更新