Bon*_*ero 7 c++ language-lawyer c++23
C++23 草案要求结构或类的后续非静态数据成员必须具有更高的地址。据我所知,早期的标准也部分地要求这样做,但是当允许编译器重新排序这些数据成员时有一些规则。这里有人能告诉我哪些规则在什么时候适用吗?
来自最新的 C++23 草案:
[expr.rel]
比较不相等指针与对象的结果是根据符合以下规则的偏序来定义的:
- 如果两个指针指向同一对象的不同非静态数据成员,或者指向此类成员的子对象,则递归地,指向后来声明的成员的指针需要比较更大,前提是两个成员都不是零大小的子对象,并且它们的类是不是一个工会。
非静态成员的分配顺序是该规则的必然结果。该规则由注释引用:
[class.mem.general]
[注 8:分配非零大小的非变体非静态数据成员 ([intro.object]),以便后面的成员在类对象 ([expr.rel]) 中具有更高的地址。
在 C++11-20 中,在提案 P1847 之前,规则是:
- 如果两个指针指向同一对象的不同非静态数据成员,或者指向此类成员的子对象,则递归地,如果这两个成员具有相同的访问控制([class. access]),两个成员都不是零大小的子对象,并且它们的类不是联合。
- 否则,两个指针都不需要比较大于另一个指针
在 C++23 之前,编译器可以使用不同的访问控制对成员进行重新排序。例子:
struct s {
int a;
protected:
int b;
};
s ab;
// value of c is implementation dependent in C++20
// value of c is true in C++23
bool c = &ab.a < &ab.b;
Run Code Online (Sandbox Code Playgroud)
主要编译器实际上没有使用除声明顺序之外的任何其他内容。
C++03 甚至更加轻松,尽管很微妙:
[类.mem]
分配未插入访问说明符声明的(非联合)类的非静态数据成员,以便后面的成员在类对象中具有更高的地址。由访问说明符分隔的非静态数据成员的分配顺序未指定(11.1)。
[expr.rel]
- 如果两个指针指向同一对象的非静态数据成员,或者指向此类成员的子对象或数组元素,则指向后面声明的成员的指针会比较更大,前提是这两个成员没有由访问说明符标签分隔( 11.1) 并且前提是他们的班级不是工会。
- 如果两个指针指向由访问说明符标签 (11.1) 分隔的同一对象的非静态数据成员,则结果未指定。