C++对象布局是否必须静态定义?

Is a C++ object layout necessarily statically defined?

本文关键字:静态 定义 对象 布局 是否 C++      更新时间:2023-10-16

更具体地说,假设A是可访问的B基类,下面的代码是否会产生未定义的行为,并且断言是否保证不会根据标准触发?

void test(B b1, B b2) {
A* a2 = &b2;
auto offset = reinterpret_cast<char*>(a2) - reinterpret_cast<char*>(&b2);
A* a1 = reinterpret_cast<A*>(reinterpret_cast<char*>(&b1) + offset);
assert(a1 == static_cast<A*>(&b1));
}

编辑: 我知道所有常见的编译器供应商都以与test隐式假设兼容的方式实现C++对象布局(即使考虑到虚拟继承(。我正在寻找的是标准中这种行为的保证(隐式或显式(。或者,还将接受标准提供的对象存储布局保证范围的合理详细描述,以证明此行为无法保证。

这可能没问题。在某些特定条件下:

A不是(部分(virtual基础,或者b1b2具有相同的最派生类型,或者你碰巧(不(幸运。

编辑:从按引用传递到按值传递的更改使得显示上述条件成立变得微不足道。

混叠规则不会妨碍,因为唯一使用的错误类型是char,并且有一个明确的例外。

除非是标准布局类型,否则很难看出在这个意义上应该如何限制实现。例如,实现是否可以对基本对象使用某种动态查找?理论上,我想,是的。(同样,在实践中,我发现很难看出偏移量是静态的并且有额外的开销应该有什么好处(

例如:

具有相同访问权限的(非联合(类的非静态数据成员 控制权(第14条(被分配,以便后来的成员有更高的 类对象中的地址。非静态的分配顺序 未指定具有不同访问控制的数据成员(第 14 条(。 实现对齐要求可能会导致两个相邻的成员 不要紧紧分配;所以可能 管理虚拟功能的空间要求 (13.3( 和 虚拟基类 (13.1(。

例如,该标准不保证虚拟基类的任何内容。

可复制或标准布局类型的对象 (6.7( 应 占用连续字节的存储空间。

同样,这仅适用于一个子集,因此该标准在这里没有多大帮助。(例如,具有虚函数的对象是非平凡的复制(。

另请参阅供应商实现的宏偏移 https://en.cppreference.com/w/cpp/types/offsetof

尽管仅针对成员变量,但即使在这里,也很明显没有太多可继续的。

如您所见,大多数事情都留给实现来决定。

另请参阅此答案(不是相同的问题,但相关(: C++继承成员地址的标准

不,原因与派生类或reinterpret_cast无关:指针算术不能保证在数组上下文之外返回原始答案。请参阅 5.7.4-5 (expr.add(,其中指定何时有效添加/减去指针:

当在指针中添加或减去具有整型类型的表达式时,结果具有以下类型 的指针操作数。如果指针操作数指向数组对象的元素,并且数组 足够大,结果指向与原始元素偏移的元素,使得 生成的数组元素和原始数组元素的下标等于积分表达式。 ...如果指针操作数和结果都指向同一数组对象的元素,或者一个过去 数组对象的最后一个元素,求值不得产生溢出;否则,行为为 未定义

减法的语言有点模棱两可,但基本上说的是同一件事。