64位机器上的vptr大小是否必须为64位?

3

我很好奇为什么64位机器上vptr的大小似乎需要占用64位,以及C ++是否真正要求如此。

vptr所需做的就是指向vtable,由于vtable不能占用太多内存并且可以分组在一起,32位足以寻址它们。

您的程序有多少个类? 1000? 10000?他们平均有多少虚函数?也许100?如果编译器+链接器将所有vtable连续放置,它们不会占用超过几MB。使用32位索引到“所有vtable数组”中的特定vtable应该有效。

我之所以谈论这个问题,是因为某些具有虚函数的小类;有时我会看到一个巨大的对象数组,其中只有2个字 + vptr,而64位的vptr对内存使用量有重要影响。


1
vptr只是指向某个结构体的指针。在64位机器上,指针大小为64位。当然,您不需要所有64位来存储vptr,但通常最好将指针保留为全尺寸,而不是仅存储32位并在查找vtable时扩展指针。 - Justin
1
据我所知,它并不需要这样做。只是通常是这样实现的。 - Justin
5
C++标准中并没有要求指向虚函数表的指针,更没有明确规定它的大小要求。你基本上是在问我们为什么有人会选择你认为不太有效的方法。 - Captain Obvlious
“_How many classes_” 是指有多少种类或者有多少个实例? - curiousguy
语言律师问题?真的吗? - curiousguy
显示剩余2条评论
2个回答

3
不,不一定要64位。但是有几个原因:
  • 有可能类的第一个成员需要64位对齐,所以在这种情况下没有好处
  • 通常,vptrs不占用大量内存
  • 最有力的论点是:如果vptr是32位索引,则所有虚拟函数调用都会变慢(由于额外的内存引用),并且会生成更多的代码。这根本不值得。

请注意,有一种内存模型(ILP32,-mx32开关用于gcc)很少使用,其中指针为32位,但可以使用64位寄存器。

微调内存并不是当今重点。例如,编译器可以自由地在访问说明符之间重新排序成员(从而可以减少填充),但是我所知道的没有任何编译器这样做。


此外,模块间的虚拟调用变得更加复杂,因为每个模块都有自己的表格,那么你如何知道应该索引到哪个表格呢? - Raymond Chen
1
@RaymondChen:运行时链接器可以做到这一点:它可以将虚拟表合并成一个大表,并修复索引。但是,是的,这是一个需要解决的问题。 - geza
期待着出现错误“无法加载模块,因为全局vtable数组过于分散。” - Raymond Chen
@geza,“通常,vptrs不占用太多内存”这句话在我的情况下并不适用:我有大量由2个double和vptr组成的对象数组,因此这些vptr占用了可用内存的1/3左右。 - Michael
1
@Michael:你的情况是个例外。但请注意,对于你的情况,由于我写的第一点,32位vptrs并没有带来任何好处。在64位exes中,double通常对齐到64位,因此在vptr之后仍会有32位填充。如果64位vptrs真的对你造成了问题,你可以考虑不使用虚函数,而是为这些类编写自己的虚拟调度机制。这是可行的,如果你没有太多这样的类,可以很容易地完成。 - geza
显示剩余2条评论

1
你的怀疑是正确的,C++确实允许这样做。但16位可能不太现实。即使所有的虚函数表都比4GB大,它们通常也不会有40亿个条目。一个典型的稳定条目将是64位,因此40亿个条目需要32GB。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接