为啥gcc实现的VTT中有top_offset?

Posted

技术标签:

【中文标题】为啥gcc实现的VTT中有top_offset?【英文标题】:Why is there a top_offset in VTT implemented by gcc?为什么gcc实现的VTT中有top_offset? 【发布时间】:2018-10-23 07:52:39 【问题描述】:

这是票数最高的答案中的detailed description of VTT。但答案没有解释为什么 VTT 中有top-offset

从我的角度来看,当我们down_cast一个base指针指向derived指针时,编译器已经知道offset需要在编译时调整(当有没有虚推导),因此在以下情况下无需存储top_offset

class A 
public:
  int a;
;
class B 
public:
  int b;
  virtual void w();
;

class C : public A, public B 
public:
  int c;
;

在这种情况下,C 类型的对象的布局如下(数字假设为 32 位指针):

                           +-----------------------+
                           |     0 (top_offset)    |//why?
                           +-----------------------+
c --> +----------+         | ptr to typeinfo for C |
      |  vtable  |-------> +-----------------------+
      +----------+         |         A::v()        |
      |     a    |         +-----------------------+
      +----------+         |    -8 (top_offset)    |//why?
      |  vtable  |---+     +-----------------------+
      +----------+   |     | ptr to typeinfo for C |
      |     b    |   +---> +-----------------------+
      +----------+         |         B::w()        |
      |     c    |         +-----------------------+
      +----------+

为什么在这种情况下VTT中有top_offset我认为top_offsetvirtual base offset只需要在虚拟继承中。

【问题讨论】:

只需 google “c++ 多重继承 top_offset” 即可获得点击率。 @HansPassant 我用谷歌搜索了,但没有找到预期的答案。 @bigxiao 嗯?无论当前代码是否需要某个特定部分,vtable 仍然需要相同的布局。 @bigxiao o11c 写的是 vtable 需要相同的 layout,而不是完全一样。显然需要相同的布局:使用B 的代码将被编译为使用一种在运行时无法更改的特定布局。该布局包括顶部偏移量。 @bigxiao 对于代码通过引用获取B 并使用vtable 中的任何内容,如果它不知道它是普通B 还是B-in-C,如何如果它不知道 vtable 布局,它可以使用 vtable 吗? 【参考方案1】:
void *top(B *b)  return dynamic_cast<void *>(b); 

编译器无法在编译时确定正确的偏移量是多少。可以使用空指针、指向完整B 对象的指针或指向B 子对象的指针调用此函数。这三种情况需要区别对待。 vtable 中的偏移量是允许它工作的原因。

【讨论】:

所以 vtable 中的 top_offset 用于这种特殊情况,因此 vtable 中需要 top_offset。但在大多数情况下,top_offset 是在编译时直接确定的,而不是由一个在 vtable 中? @bigxiao 确实。在那些可以在编译时确定所需偏移量的情况下,我想不出编译器会从 vtable 加载偏移量的任何原因。 但是 “vtable 中的偏移量是允许它工作的原因。” 似乎不正确。它是 vtable 中的 type_info 对象允许 dynamic_cast 工作。有了type_info,人们总能知道B* b 的真实类型,从而知道对应的top_offset,而vtable 中没有top_offset 项。 @bigxiao 假设给定两种类型(本例中为BC),可以确定一种在另一种中的偏移量。这在编译时通常是正确的,但在运行时您最终需要再次使用相同的偏移量。此外,在“钻石问题”(同一个基类被多次继承)的情况下,即使在编译时也无法确定。 菱形问题应该在编译时确定。但是,无论如何,我同意在使用dynamic_castvoid*时在vtable中使用top_offset更方便。跨度>

以上是关于为啥gcc实现的VTT中有top_offset?的主要内容,如果未能解决你的问题,请参考以下文章

gcc std::unordered_map 实现速度慢吗?如果是这样 - 为啥?

如何在 tvOS 中将外部 .vtt 字幕文件添加到 AVPlayerViewController

为啥 GCC 为 C++ <cmath> 实现 isnan() 比 C <math.h> 更有效?

为啥在 GCC 5.1 中仍然启用 COW std::string 优化?

为啥 GCC 没有尽可能地优化这组分支和条件?

为啥 GCC 编译的应用程序总是包含 _mcount 符号?