我在C ++中有一个简单的类,它有一个整数和一个vtable:
class Something {
virtual void sampleVirtualMethod();
int someInteger;
};
如果您查看MSVC的对象布局(使用/ d1reportSingleClassLayout),您将获得:
class Something size(8):
+---
0 | {vfptr}
4 | someInteger
+---
这完全有道理。 vtable指针为4个字节,整数为4个字节。奇怪的是当我在课堂上添加一个双精度词时:
class Something {
virtual void sampleVirtualMethod();
int someInteger;
**double someDouble;**
};
我得到了这个对象布局:
class Something size(24):
+---
0 | {vfptr}
8 | someInteger
| <alignment member> (size=4)
16 | someDouble
+---
为什么0 offset和someInteger 8之间的差异而不是4? vtable是否以某种方式增长到8个字节?无论我添加双精度的顺序如何,都会发生这种情况。
感谢。
答案 0 :(得分:2)
This blog post讨论了同样的问题,并在Jan Gray的评论中作了解释,他很久以前就编写了布局代码MS C ++编译器。
为了解释,只有在布局了其他数据成员之后,才会将vfptr插入到类布局中。根据数据成员的对齐要求,这意味着可能引入不必要的填充。如果类没有带有vfptr的基类,也只会发生这种情况。
因此,解决方法在博客文章中提供:
class EmptyBase
{
protected:
virtual ~EmptyBase() {}
};
class Something : public EmptyBase {
virtual void sampleVirtualMethod();
int someInteger;
**double someDouble;**
};
在这种情况下, sizeof(Something)
应为16。
答案 1 :(得分:1)
我怀疑this answer与它有关。引用dirkgently的答案,引用GCC手册:
请注意,ISO C标准要求任何给定结构或联合类型的对齐至少是所讨论的结构或联合的所有成员的对齐的最低公倍数的完美倍数。 / p>
根据该规则,一旦你添加了一个8字节的双精度数,编译器必须将所有内容安排在8字节的倍数上。当然,您可以使用#pragma pack()覆盖它,尽管如果您在8字节边界以外的其他内容上使用8字节成员,效率会降低。
答案 2 :(得分:0)
我无法直接回答你的问题,因为编译器的行为没有好的借口。相反,我会沉迷于疯狂的猜测,因为还没有答案。
我怀疑对齐算法中的错误是这样的:
如果这个bug存在,我怀疑它是编译器早期作为一个4字节对齐的C编译器遗留下来的。现在,编译器的默认值为/Zp8
,这意味着每个结构至少对齐到8个字节,因此无论如何都不需要修复“第一个”成员的对齐。
此致 Sherm