对相同基类的引用在内存中必须具有单独的偏移量
References to the same base classes must have separate offsets in memory
我发现编译器与该程序之间存在一些不一致,
struct A {
};
struct B : public A {
float m;
};
struct C : public A {
B b;
float n;
};
struct D : public A {
float n;
B b;
};
static_assert(sizeof(A) == 1, "");
static_assert(sizeof(B) == 4, "");
static_assert(sizeof(C) == 8, ""); // most compilers say this is 12
static_assert(sizeof(D) == 8, "");
大多数编译器断言 sizeof(C) == 8 说 sizeof(C) 实际上是 12。我发现唯一没有并说它是8的编译器是Visual Studio 2010 Microsoft。
比我聪明的人告诉我的原因是,在 B 中有两个单独的 A 引用需要保留彼此不同的单个偏移量。首先,从 C 派生的 A 位于偏移量 0,成员 b 内部的第二个 A 不能与第一个 A 位于 0 处的偏移量相同,因此插入了 4 个字节的填充。
由于大多数编译器都实现了这种行为,我想知道您需要什么情况来确保两个 A 具有不同的引用?寻找一些直觉来解释为什么会这样?
有人说这可能是标准要求的条件,我们很好奇它的原因是什么?
谢谢
该标准明确要求同一类型的每个对象的地址不同。相关条款是5.10 [expr.eq]第1段:
当这是且仅当两个相同类型的指针都为 null、都指向同一函数或都表示相同的地址 (3.9.2) 时,它们才相等。
区分这两个对象所必需的。对象同时具有值和标识。对于基类子对象,与包含类具有相同的地址是合理的。对于类的成员,您可以通过类型来区分两个对象的身份,即它们可以具有相同的地址。对于两个相同类型的对象,您仍然需要一些东西来区分对象的标识。
是的,这在 10p8 中提到:
基类子对象的大小可能为零(条款 9);但是,两个 具有相同类类型且属于相同类的子对象 大多数派生对象不得在同一地址 (5.10) 分配。
在C
中,您有两个A
,一个是继承的,另一个是B
的一部分。Microsoft在这里积极而错误地使用了不应该使用的空基类优化。我相信这是已知的错误,但是在Microsoft Connect上确实很难找到错误报告。
在C++中,对象由一对数据唯一确定:它的地址和类型。
正如您正确观察到的那样,C
和 D
都包含两个不同的子对象A
对于它们来说,这必须是真的。但是,根据您在内存中布置B
的方式,您可以看到可能无法将两个A
子对象放在 8 字节结构中的不同地址。
为什么不打印出子对象的实际数字地址?
- 有没有办法将谓词中的元素偏移量传递给 std 算法?
- 通过指针偏移量访问结构变量值
- 以线程安全的方式转换 C/C++ 中时区名称字符串的时区偏移量
- librdkafka:rd_kafka_assignment 返回分配分区的偏移量 -1001
- 是否通过向封闭对象的地址添加字节偏移量来访问子对象
- 向指针地址添加 20 个字节偏移量
- glMapBufferRange(..) 中的偏移量关系和 glDrawArraysInstanced(..) 中的第一
- 是否有与 C# Structs/StructLayout 等效的功能,C++中的字段偏移量?
- 我的 sumASCII 函数中的此偏移量是多少?
- boost::序列化中的派生类偏移量计算.有效吗?
- RedisGraph 语法错误在偏移量 8 靠近"创建"
- 胎面偏移量的时间复杂度?
- 如何从 c++ 中的给定标准输入中获取每个字符的偏移量?
- 编译器在构造函数中计算的成员偏移量不正确
- 使用基地址和偏移量获取变量的地址
- c++ 读取进程内存基址 + 偏移量不起作用
- 通过其在 C 中的偏移量调用函数
- ld:无效的字符串偏移量...对于".strtab"部分
- GDB 显示损坏的指令地址偏移量
- 对相同基类的引用在内存中必须具有单独的偏移量