如果类包含基类类型的成员作为第一个元素,后跟其他成员,编译器是否可以优化空基?

Can the compiler optimize out the empty base if the class contains a member of base class type as first element, followed by other members?

本文关键字:成员 是否 编译器 其他 优化 类型 基类 如果 元素 第一个 包含      更新时间:2023-10-16

考虑:

struct empty {};
struct child : empty {
empty a[sizeof(int) / sizeof(empty)];
int b;
};
// Assume sizeof(int) >= sizeof(empty)

sizeof(child)的标准要求是否超过2 * sizeof(int)

在我看来,没有什么可以阻止baseclass-sub对象与成员b共享其地址。

如果没有,是否有任何常见的 ABI 利用它?

我们首先检查允许空基类优化以熟悉术语的规则:

N4659 标准草案 [介绍对象]

7 除非是位域(12.2.4(,否则派生对象应具有非零大小,并应占用一个或多个 字节的存储。基类子对象的大小可能为零。[截图]

然后是关于不同地址的要求:

8 除非对象是位字段或大小为零的基类子对象,否则该对象的地址是地址 它占用的第一个字节。两个具有重叠生存期但不是位字段的对象 a 和 b 可能具有 如果一个嵌套在另一个中,或者至少有一个是零大小的基类子对象,则使用相同的地址,并且 它们属于不同的类型;否则,它们具有不同的地址。

空的基子对象和成员数组的第一个元素可能不具有相同的地址,因为它们的类型相同。

因此,如果我们假设基子对象必须在成员之前排序,并且成员必须按声明顺序排序,则需要填充来实现不同的地址。但是,我在标准中找不到需要这种顺序的规则。

可移植的Itanium C++ABI(由Clang和GCC使用(确实指定了顺序,并且在该规范下,确实需要填充:

2.4 非 POD 类类型

二、虚拟基地以外的会员分配

对于每个数据组件 D(首先是 C 的主基,如果有,然后是声明顺序中的非主、非虚拟直接基类,然后是声明顺序中的非静态数据成员和未命名位字段(,分配如下:

如果不同的 ABI 允许在内存布局中的基数之前使用非声明顺序子对象或成员子对象,则它可能能够在此处利用 EBCO。至少作为空底座的特殊情况。我不知道这样的 ABI 是否存在。

从规范中可以吗?是的。[class.mem]/24 告诉我们标准布局类的地址与其第一个基类子对象之间的关系。但该标准没有说明非标准布局类型的这种关系。由于您的类型不是标准布局,因此标准没有说明该位置。

基类分配通常有两种 ABI 形式:将它们放在成员之前或放在成员之后(对于非标准布局类型(。在成员之后分配基类的 ABI 可以自由地为空基类分配最后一个有效地址,并在类的存储区域中适当对齐。如果它碰巧以避免违反 [intro.object]/8(子对象的唯一标识(的方式着陆,那么它可以执行该分配。

两个最常见的 ABI,Windows 和 Itanium,都在成员之前分配基类。虽然这样的 ABI 可以更随意地分配基类,但它们不会费心这样做。无论如何,这只会出现在模板代码中,因为空类是的。它们的行为都相同,因此没有理由故意将它们同时作为基类和成员。

那么,为什么要为如此罕见的案件制定复杂的 ABI 规则呢?