布局上的POD类型的大小和对齐,由基本的C ABI指定,但有以下附带规定:
- 如果基本ABI为
C99类型_Bool指定了规则,则bool将遵循这些规则。否则,它的大小和对齐为1。 - 如果基本ABI没有为空类指定规则,则空类的大小和对齐为1
- 类型
T &和T &&与指针类型T*的大小与对齐完全相同 - 成员指针类型被视为一个特定的C类型处理,详见
这些类型的_dsize_、_nvsize_和_nvalign_被定义为它们常规的大小和对齐。这几个属性只在非空类作为基类时才会用到,普通POD类型不需要单独考虑它们。对于POD类型,我们会忽略其尾部填充,因为:
- ①在
CWG(Core Working Group)问题43被解决之前,标准不允许我们将尾部填充用于其他用途; - ②忽略尾部填充有时能让该类型的拷贝操作更快。
Paw5zx个人理解:点击查看更多
这里的忽略,应该指的是早期C++标准禁止复用尾部填充来存放额外成员,所以ABI只能把它保留为占位符
Paw5zx个人理解:点击查看更多
根据C++ Standard Draft 的2025-07-25版本中的内容
POD类是:
- 具有trivial和standard-layout属性的类,并且
- 其所有非静态数据成员都不能是非POD类类型或非POD类类型的数组
平凡相关定义:
平凡类(trivial class):
- 是一个平凡可复制类
- 有一个或多个可用(
eligible)的默认构造函数,并且所有这些默认构造函数都是平凡的
平凡可复制类(trivial copyable class):
- 至少有一个可用的拷贝构造函数,移动构造函数,拷贝赋值运算符或移动赋值运算符,并且
- 每个可用的拷贝构造函数,移动构造函数,拷贝赋值运算符和移动赋值运算符都是平凡的,并且
- 有平凡的、非删除的析构函数
平凡默认构造函数:
类X的默认构造函数是平凡的,当且仅当同时满足以下条件:
- 它不是用户提供的,并且
- X没有虚函数以及虚基类,并且
- X的所有非静态数据成员都没有默认初始值,并且
- X的所有直接基类都具有平凡默认构造函数,并且
- 要么X是个联合体,要么X所有非静态类类型成员(或类类型数组)的默认构造函数也是平凡的
平凡拷贝/移动构造函数:
类X的拷贝/移动构造函数是平凡的,当且仅当同时满足以下条件:
- 它不是用户提供的,并且
- X没有虚函数以及虚基类,并且
- X的所有直接基类的拷贝/移动构造函数也是平凡的,并且
- X所有非静态类类型成员(或类类型数组)的拷贝/移动构造函数也是平凡的
平凡析构函数;
类X的析构函数是平凡的,当且仅当同时满足以下条件:
- 它不是用户提供的,并且
- 非虚,并且
- X的所有直接基类都有非平凡析构函数,并且
- 要么X是个联合体,要么X所有非静态类类型成员(或类类型数组)的析构函数也是平凡的
standard-layout相关定义:
类S是标准布局类,当且仅当同时满足以下条件:
- 没有非标准布局类类型的非静态数据成员(或者非标准布局类类型数组),没有引用类型的成员
- 没有虚函数以及虚基类
- 所有非静态数据成员的访问控制(
public、protected、private)必须相同 - 所有基类都是标准布局类
- 每个基类类型(类型任意)至多有一个子对象
- 所有非静态数据成员和位域必须在同一个类中首次声明,要么在都基类中,要么在都派生类中,不可分散
- 基类不能是集合
M(S)中的类型,对于类型X来说,M(X)定义如下:- 如果X是一个没有非静态数据成员的非联合体类类型,那么集合M(X)为空
- 如果X是一个非联合体类类型,且具有类型为X₀的非静态数据成员,该成员要么是零大小的,要么是X的第一个非静态数据成员(该成员可以是匿名联合体),则集合M(X)由X₀和M(X₀)的元素组成。
- 如果X是一个联合体类型,则集合M(X)是所有M(Uᵢ)的并集以及包含所有Uᵢ的集合的并集,其中每个Uᵢ是X的第i个非静态数据成员的类型。
- 如果X是元素类型为Xₑ的数组类型,则集合M(X)由Xₑ和M(Xₑ)的元素组成。
- 如果X是非类、非数组类型,则集合M(X)为空。
M(X)是所有可以在X的0偏移量处存在的所有非基类子对象的类型的集合,即如果某个类型T即做为S的基类出现,又属于M(S),那么S不是标准布局类。