后文会用到以下名词,本文中给出它们的定义:
alignment of a type T (or object X)
对齐:一个值A,使得任何具有类型T的对象X的地址满足&X % A == 0的约束。
base class of a class T
基类:当本文档提到base class of a class T时,除非另有说明,它指的是T本身以及那些所有直接或间接、虚或非虚地派生出T的类。另外,我们使用严格基类(或者叫真基类)(proper base class)将T本身排除在列表之外。
Paw5zx个人理解:点击查看更多
base class指是T及其所有父类,而proper base class指的是T的所有父类(不包括T)
basic ABI properties of a type T
基本ABI属性:由基础C ABI决定的一种类型的基本表示属性,包括它的大小、对齐、调用约定(calling conventions)中对其的处理方式以及指向该类型的指针的表示方式。
base object destructor of a class T
基础对象析构函数:一个函数,负责执行T的非静态数据成员和T的非虚直接基类的析构函数。
complete object destructor of a class T
完整对象析构函数:一个函数,除了执行基础对象析构函数所需的操作外,还负责执行T的虚基类的析构函数。
deleting destructor of a class T
删除析构函数:一个函数,除了执行完整对象析构函数的所有操作外,还会调用适当的内存释放函数(如delete运算符)。
direct base class order
直接基类顺序:当将一个类的直接基类视为有序集时,此顺序是它们在声明中的顺序,从左到右。
diamond-shaped inheritance
菱形继承:一个类具有菱形继承,当且仅当它有一个虚基类,该虚基类可以通过多个直接基类的不同继承图路径到达。
Paw5zx个人理解:点击查看更多
菱形继承应该描述的是一个类继承结构,位于顶部的基类可以通过多个路径到达,这个定义本身应该并不严格要求顶端的基类必须是通过虚拟继承的。
对于此定义是否限制顶端基类一定要通过虚拟继承,待验证。此名词的使用在2.9.4 RTTI Layout,阅读完再回来更新此条目。
dynamic class
动态类:需要虚表指针的类(因为它或它的基类有一个或多个虚成员函数或虚基类)
Paw5zx个人理解:点击查看更多
原文:
A class requiring a virtual table pointer (because it or its bases have one or more virtual member functions or virtual base classes) is called a dynamic class.
这里的virtual table pointer应该是泛指任意需要运行时表格指针的情况(vptr和vbptr)
empty class
空类:一个类,没有非静态数据成员(除了空数据成员(empty data member)),没有匿名位域(除了零宽位域),没有虚函数,没有虚基类,没有非空非虚的严格基类。
Paw5zx个人理解:点击查看更多
空类,满足以下条件:
- 无非静态数据成员:除了空类类型的非静态数据成员以外,没有其他类型的非静态数据成员(可以有静态成员)
- 无匿名位域:除了宽度为零的位域之外,没有任何匿名位域(零宽位域通通常用于强制对齐,但不存储实际数据)
- 无虚函数:可以有成员函数,但是不可以是虚函数(因为有虚函数,类内就会有虚表指针,就会有内存占用)
- 无虚基类:
- 无非空非虚严格基类:只能非虚继承空类
空类常用于空基类优化(Empty Base Optimization, EBO)
对于空类T,有:sizeof(T) == 1,确保了每个实例都有独立的内存地址
1 | //Empty是空类 |
empty data member
空数据成员:空类类型的潜在重叠非静态数据成员
inheritance graph
继承图:继承关系拓扑图,其中节点表示一个类及其所有子对象,用有向边将每个节点与其直接基类相连。
inheritance graph order
继承图顺序:通过深度优先遍历继承图获得的类对象及其所有子对象的顺序,从最派生类的对象到基类对象,其中:
- 没有节点会被访问超过一次(所有节点被访问次数小于等于1)。(因此,虚基类子对象及其所有基类子对象将只被访问一次)
- 一个节点的子对象按照它们被声明的顺序访问。(例如,给定
class A : public B, public C,首先遍历A,然后是B及其子对象,然后是C及其子对象。)
请注意:遍历可以是先序遍历,也可以是后序遍历。除非另有说明,否则按照先序遍历(派生类在基类之前)。
instantiation-dependent
An expression is instantiation-dependent if it is type-dependent or value-dependent, or it has a subexpression that is type-dependent or value-dependent. For example, if
pis a type-dependent identifier, the expressionsizeof(sizeof(p))is neither type-dependent, nor value-dependent, but it is instantiation-dependent (and could turn out to be invalid if after substitution of template argumentspturns out to have an incomplete type). Similarly, a type expressed in source code is instantiation-dependent if the source form includes an instantiation-dependent expression. For example, the type formdouble[sizeof(sizeof(p))](withpa type dependent identifier) is instantiation-dependent.
暂略
morally virtual
逻辑虚拟:如果X是Y的虚基类,或是Y的虚基类的直接或间接基类,那么Y的子对象X就是Y逻辑上的虚基类。
nearly empty class
近似空类:一种包含虚指针,并且除了(可能存在的)虚基类之外没有其他数据的类。具体来说,它:
- 没有非静态数据成员,没有非零宽的匿名位域;
- 如果这个类具有直接基类,那么这些基类必须符合三种情况之一或组合:empty,nearly empty,virtual;
- 最多有一个非虚,近似空的直接基类;
- 没有任何空,非逻辑虚拟,偏移量非零(在派生类的内存布局中不位于起始位置)的严格基类。
这样的类即使是虚的,也可以是主基类,可以与派生类共享虚指针。(这种类最适合用来做primary base class)
Paw5zx个人理解:点击查看更多
近似空类的本质在于它是一个只因虚机制而存在的开销的最小的类。它的核心目的是让ABI能高效复用虚表指针和基类的布局,从而避免无意义的对象体积膨胀。
编译器可以将其他空基类或近似空基类折叠到虚表指针所在的空间(offset 0)
non-trivial for the purposes of calls
A type is considered non-trivial for the purposes of calls if:
- it has a non-trivial copy constructor, move constructor, or destructor, or
- all of its copy and move constructors are deleted.
This definition, as applied to class types, is intended to be the complement of the definition in [class.temporary]p3 of types for which an extra temporary is allowed when passing or returning a type. A type which is trivial for the purposes of the ABI will be passed and returned according to the rules of the base C ABI, e.g. in registers; often this has the effect of performing a trivial copy of the type.
暂略
POD for the purpose of layout
布局上的POD类型:通常,如果一个类型是POD类型(详见2003版ISO c++ [basic.types]),则这个类型被认为是布局上的POD类型。
一个类型将不会被视为布局上的POD类型,当它:
- 是一个POD-struct或POD-union(详见ISO c++ [class]),但其声明的位域宽度大于声明的位域类型,或
- 是一个数组类型,其元素类型不是布局上的POD类型,或
- 是一个POD-struct,其具有一个或多个潜在重叠的非静态数据成员。
在本段中引用ISO C++的地方,是指该标准的Technical Corrigendum 1版本。
注意:ISO C++标准已经发布了多个修订版,每个修订版都包含了不同的POD定义。为了确保根据标准的不同版本编译的代码的互操作性,有必要为平台确定一个单一的定义。平台供应商可以选择遵循标准的不同版本,但是默认情况下,此ABI下的POD定义是2003年版本(TC1)中的定义。
绑定到TC1中对POD的定义并不妨碍编译器完全符合后来的修订。本ABI规则内使用POD定义仅用来决定是否在基类子对象的尾部填充中分配对象。随着时间的推移,这些标准已经扩展了POD的定义,而且它们也禁止程序员使用memcpy直接读取或写入基类子对象的底层字节。因此,即使在最保守的解释中,实现也可以在任何在C++98中不是POD类型的类的尾部填充中自由分配对象。本ABI也满足这种情况。
potentially-overlapping subobject
潜在重叠子对象:一个潜在重叠子对象是:
- 基类子对象,或
- 用
[[no_unique_address]](C++17)特性声明的非静态数据成员
Paw5zx个人理解:点击查看更多
潜在重叠子对象是指在对象内存布局中,可能与其他子对象共址的部分,包括基类子对象和声明了[[no_unique_address]]的非静态成员变量
primary base class
主基类:对于一个动态类来说,主基类(如果存在的话)是一个与动态类在偏移量0处共享虚表指针的唯一基类。
secondary virtual table
次级虚表:嵌入在派生类虚表中的基类的虚表实例
templated entity
暂略
thunk
thunk:(在此ABI中)thunk是与目标函数相关联的一段代码,它会在控制权转移至目标函数之前被调用,而不是直接调用目标函数,目的是为了修改参数(例如this指针)或环境的其他部分,并且可能在函数返回后执行进一步修改。一个thunk:
- 可能只包含一条指令,执行后直接过渡到紧随其后的目标函数,或者
- 可能是一个完整的函数,它有自己的堆栈帧,并对目标函数进行完整的调用。
vague linkage
暂略
virtual table (or vtable)
虚表:一个动态类有一个与之关联的虚表(一个动态类可能有多个虚表实例(多重继承情况下);但不是每个对象一个(对象不拥有独立的虚表,所有相同类型的对象都会共享同一个虚表)),表内存储了有关类的动态属性的信息,例如:虚函数指针,虚基类偏移量等。
virtual table group
虚表组:一个集合,包括类的主虚表以及该类的所有严格基类对应的的次级虚表